Introduction to Communications Programming | Common Communications Interface |
The Common Communications Interface (CCI) is an Application Programming Interface (API) which enables you to build communications capabilities into your applications. CCI is designed to enable a programmer to produce applications which initiate, control, and terminate a conversation with another application on either the same machine, or on another machine on a connected network. The network and its interface are hidden from the programmer and the end user.
CCI enables programs to access communications media in a consistent manner, irrespective of the communications protocol or operating environment. Programs written using the CCI API can communicate using any of the supported communications protocols.
CCI comprises a suite of modules, each module supporting a particular communications protocol. For example, the CCITCP module supports the TCP/IP communications protocol.
Using CCI, you can connect applications executing in one user session with other applications executing in another user session on the same machine or on another machine/workstation and transmit data using simple send, receive, suspend, resume, and terminate function calls.
CCI is used by Fileshare Version 2, Fileshare for Host Systems, MTS, Probe, and the cooperative animation facilities of this COBOL system. CCI is also used by the Application to Application Interface (AAI) product to provide communications facilities for Remote Procedure Calls (RPC).
CCI modules are provided for the following communications protocols and environments:
Protocol | Module | DOS | NLM | Windows | Windows NT | OS/2 16-bit | OS/2 32-bit | UNIX |
---|---|---|---|---|---|---|---|---|
LU6.2 | CCIAPPC | x | x | x | x, | |||
DDE | CCIDDE | x | x | , | ||||
Novell IPX | CCIIPX | x | x | x | x | x, | ||
LU2.0 | CCILU2 | x | x | x | x, | |||
Named Pipes | CCINAMP | x | x, | |||||
UNIX Named Pipes | CCINAMPU | x | ||||||
NETBIOS | CCINETB | x | x | x | x, | |||
TCP/IP | CCITCP | x | x | x | x | x | x |
Note: The CCI modules are not supported in virtual environments, such as Windows running under OS/2.
On DOS, Windows and OS/2, the CCI modules are provided as .exe, .dlw, or .dll files so that you can call CCI dynamically from your program. They are also provided in .obj and/or .lib files so that you can statically link the CCI modules with your .obj modules. The .lib files for CCI are named as follows:
DOS:
filenamed.lib
Windows:
filenamew.lib
OS/2:
filename.lib
CCI is implemented as a set of API functions which you can call from your program. A summary of the available CCI functions, in alphabetical order, is given below. See the chapter Common Communications Interface for full syntax details.
CCI-Closeclient | Requests the disconnection of a client from a server. |
CCI-Closeserver | Requests the termination of a server. |
CCI-Connect | Establishes a connection between a server and a client. |
CCI-Geterror | Returns an error message for the last reported error. |
CCI-Hangup | Requests the disconnection of a server from a client. |
CCI-Initclient | Establishes a connection between a client and a server. |
CCI-Initserver | Initializes a server. |
CCI-Query | Determines whether an aynchronous request has completed. |
CCI-Receive | Receives a message. |
CCI-Receivall | Reads a message from any client targeted at a server. |
CCI-Resumeclient | Prepares a connection between a client and a server. |
CCI-Resumeserver | Prepares a connection between a server and a client. |
CCI-Send | Sends a message. |
CCI-Suspendclient | Suspends a connection between a client and a server. |
CCI-Suspendserver | Suspends a connection between a server and a client. |
CCI-Timeout | Overrides the default timeout. |
CCI-Trace | Traces information to a log file. |
CCI-Transact | Executes a synchronous CCI-Send followed immediately by a synchronous CCI-Receive. |
CCI-Wait | Waits until an asynchronous request has completed. |
Before your program can use CCI, an initialization call must be made. This call enables the CCI routines to be called via a PROCEDURE-POINTER table which should be located in the Linkage Section of your program. A set of copyfiles are supplied for this purpose:
CCI can be dynamically or statically linked on DOS, Windows, OS/2 and UNIX.
The CCI API is called using the standard COBOL call convention (CALL-CONVENTION 0). The CCI API can be called from C and Assembler programs as well as COBOL.
The CCI API can also be called using the Pascal call convention (CALL-CONVENTION 3) on those environments that support this type of calling convention (DOS, Windows and OS/2). If you use this call convention from COBOL, you will need to set up the Pascal call convention using the CALL-CONVENTION 3 statement in the Special-Names paragraph and use this in each call statement.
Versions of CCI prior to Version 2 (that is, those available with
Version 3.0 and earlier of this COBOL system) used only the Pascal call
convention and passed some parameters BY VALUE. This interface is
documented in the chapter Calling CCI Functions By Value. However,
the current COBOL interface is simpler, so you may find it useful to
change the calls in any existing code. You can determine the CCI version
in use on your system by inspecting the CCIVERSN
parameter returned by the CCI initialization call.
The default call convention (CALL-CONVENTION 0) syntax is:
call "module-name" using param-block
where the parameters are:
The format of param-block
is as follows:
01 param-block. 03 signature. 05 CCISIGN PIC X(6). 05 CCITYPE PIC X(8). 05 CCIVERSN PIC X(6). 03 table-pointer USAGE POINTER.
where on return:
The file ccitab.cpy contains the call table, shown below:
01 proctab. 03 CCI-Initserver procedure-pointer. 03 CCI-Closeserver procedure-pointer. 03 CCI-Initclient procedure-pointer. 03 CCI-Closeclient procedure-pointer. 03 CCI-Hangup procedure-pointer. 03 CCI-Send procedure-pointer. 03 CCI-Receive procedure-pointer. 03 CCI-Receiveall procedure-pointer. 03 CCI-Transact procedure-pointer. 03 CCI-Connect procedure-pointer. 03 CCI-Wait procedure-pointer. 03 CCI-Query procedure-pointer. 03 CCI-Resumeclient procedure-pointer. 03 CCI-Suspendclient procedure-pointer. 03 CCI-Resumeserver procedure-pointer. 03 CCI-Suspendserver procedure-pointer. 03 CCI-Geterror procedure-pointer. 03 CCI-Trace procedure-pointer. 03 CCI-Timeout procedure-pointer.
Each function sets the special register RETURN-CODE to zero for success, and non-zero for failure. See the section CCI Error Codes in the chapter Common Communications Interface for a list of possible return codes.
When CCI is statically linked, the definition of the procedure pointer table in the Linkage Section is not required, but can still be used.
If you do not use the procedure pointer table, the CCI functions can be called by name (for entry point names within the supplied .lib modules) using the same names as those defined in the procedure pointer table above, but using the format "_CCI_protocol_Initclient". For example, to call a statically linked CCI-Initclient from COBOL on machines requiring an underscore (_) prefix before a high-level language reference (for example, any PC running DOS, Windows 3.x or OS/2), you would code the following:
call api "_ CCI_IPX_Initclient" using srvrname machinename sessid async cciend.
On machines not requiring an underscore prefix (for example, some UNIX
machines), you omit the leading "_" from CCI_IPX_Initclient
.
CCI programs use four-byte numeric values (a serverhandle
)
to distinguish between different servers and four-byte numeric values (a
sessionid
) to differentiate between different
connections within a single client or server.
As CCI uses four-byte numeric handles to denote differing services and
connections to those services (sessions), a serverhandle
is used in all calls which deal with services as whole elements.
These calls are:
A session identifier
is used to refer to each unique connection between a client and
server. The value of the sessionid
can differ
between server and client program elements, although within the relevant
application segment (server or client) the sessionid
always uniquely identifies a specific connection.
A specific sessionid
is returned only from
CCI-Initclient, CCI-Connect or CCI-Receiveall and is used for every
operation that is specific to that session connection from that point
onward.
A server can be regarded as an element within a single program that supplies a service which is located on, or visible to, a network. Clients then contact the service, establishing a session with the server.
Many CCI functions have a four-byte parameter: async
.
This can be used to implement asynchronous function calls.
If async
contains 0, the CCI function executes
synchronously; that is, it does not return control to your program until
either the operation is complete, an error occurs, or a timeout occurs.
If async
contains -1, the CCI function returns
control to your program immediately although the function call itself does
not complete. If an error occurs, it is reported at this point.
CCI uses the four-byte storage location referred to as async
to store a handle containing the return code of the call. This handle can
be interrogated by the CCI-Query or CCI-Wait functions. You should not
check the value of any parameter passed to a CCI function which is
executing asynchronously until either a CCI-Query or CCI-Wait function has
completed. Care should be taken when implementing asynchronous function
calls. Full support for the asynchronous calls is provided on
multi-tasking platforms
such as Windows, OS/2 and UNIX. However, DOS systems can suffer
performance degradation under certain circumstances because of the way in
which some protocol providers implement DOS application interfaces; that
is, it is assumed that under DOS, any calling process has complete control
of the machine on which it is executing, and a call to the underlying
communications interface can have the effect of hanging the machine until
the call completes or times-out. This in itself is not a fault, but
something that you should be aware of.
When designing applications which make use of asynchronous CCI functions, it is worth remembering that CCI session connections are all full-duplex, which means that it is permissible to have an outstanding asynchronous CCI-Receive function and an outstanding CCI-Send function operating concurrently on the same session. This is true of all data transmission functions (CCI-Send, CCI-Receive, CCI-Receiveall) which support an asynchronous calling method. It is not permissible, however, to change the state of the session using any of the CCI-Suspend or CCI-Hangup/CCI-Closeclient functions while any asynchronous CCI-Send or CCI-Receive operations are outstanding.
When a CCI call returns with a timeout value in the RETURN-CODE, it means that the call took longer than the specified time period to complete.
A timeout can occur as a result of any CCI function call. When a timeout results from a CCI-Query or CCI-Wait function call, it refers to the original CCI function call.
A CCI operation that times out can be re-tried using the same type of call, or you can design your program to take this opportunity to perform some other task.
The CCI-Trace function enables you to trace CCI function calls made by
your application. To trace a call, you must include the CCI-Trace function
before the start of the code segment on which a trace is required, setting
the CCI-Trace toggle
parameter to 1 (enable trace).
At the end of the code segment, include another CCI-Trace function call,
this time with the toggle
parameter set to 0
(disable trace).
The information obtained from the trace is written to a log file which, by default, is called ccitrace.log. In addition to the trace information, CCI data and flow control information can be sent to the log file, depending on the options you specify when calling CCI-Trace.
Although the trace log file is not generally in a readable format, any data output from the CCI data buffers will not be encrypted when placed in this file.
CCI-Trace is not available under DOS. Any call to CCI-Trace from this environment is ignored.
There are two methods of specifying the level of tracing: the CCITRACE environment variable and the control-buffer parameter passed to a CCI-Trace function call.
You can set the CCITRACE environment variable as follows:
CCITRACE=filename [options]
where:
filename |
is the name of the log file you want the trace output
to go to. If you do not specify this parameter, the log file ccitrace.log
is created in the current directory with all options
set to their default states. |
options |
can be any one, or all, of the following, and must be
upper case:
|
The control-buffer parameter is a text string which is passed to a CCI-Trace function call in order to specify the level of tracing required. It can take the same values as those specified for the CCITRACE environment variable above.
Note: The settings of the CCITRACE environment variable overwrite values specified in control-buffer.
See CCI-Trace in the chapter Common Communications Interface for further information.
Every CCI function call must be allowed to terminate before the calling program is canceled or the conversation session is terminated. This condition is automatically satisfied for synchronous operations, but for asynchronous operations it is the caller's responsibility.
All asynchronous function calls must be carried through to completion. Asynchronous functions have completed either if the original call returns a non-zero error code, or when a CCI-Wait or CCI-Query returns a code other than -1. Failure to properly terminate an asynchronous call ties up system resources.
An asynchronous function call is implicitly canceled by closing the session or server handle, and will terminate almost immediately.
Outstanding asynchronous CCI-Connect, CCI-Receiveall, and CCI-Resumeserver requests should be allowed to terminate before executing a CCI-Closeserver for that server handle.
An outstanding asynchronous CCI-Resumeclient request should be allowed to terminate before executing a CCI-Closeclient for that session.
Outstanding asynchronous CCI-Receive and CCI-Send requests should be allowed to terminate before executing a CCI-Closeclient or CCI-Hangup for that session.
In most client/server architectures, the client initiates communication with a server and, once the connection is established, makes requests to the server using a set of API function calls.
There are three general types of connection between a server and a client:
A single server connects to a single client.
A single server connects to many clients, possibly at the same time.
Multiple servers connect to each other and to separate client parts of the same overall application.
When designing a client/server application, it is a good idea to use a modular approach, with each module containing common elements of the application. For example, you could construct a module which contains elements which are used by all protocols - such as send and receive. This forms a set of service modules which are called by the main application element. In this way, the elements should be usable in future applications with little or no modification. Porting your application between protocols and operating systems is also made simpler with a good modular design.
Both the client and server elements of the basic design can be divided into three areas of operation:
Data is transferred when corresponding send (CCI-Send) and receive (CCI-Receive) functions occur on either side of a conversation between a server and a client.
Once a connection has been established between a client and a server, the client sends data using the CCI-Send function. The server must issue a corresponding CCI-Receive in order to accept the data.
To keep open the connection between the server and the client for multiple data transfers, both the server and client must use corresponding CCI-Send and CCI-Receive functions until all data in that session has been transferred.
Send and receive calls can be made as a single call using CCI-Transact. This function links a single synchronous send with a single synchronous receive in a single call.
System control consists of corresponding pairs of CCI-Resume and CCI-Suspend functions.
A CCI-Resume function must follow each CCI-Init function for data transfer to take place and a CCI-Suspend function must precede each CCI-Close function.
A CCI-Resume function call must precede the data transfer functions, CCI-Send and CCI-Receive, and a CCI-Suspend function call must follow them although it is not necessary to call CCI-Resume and CCI-Suspend each time the data transfer functions are used.
The CCI-Resume and CCI-Suspend functions on the server and client are used to start and stop conversation segments which can be resumed at a later stage. At a lower level, these functions are used by CCI to allocate and release system resources on those protocols where it is possible to do so. This allows as many connections as possible to be sustained from one machine.
For short sessions, you may find it beneficial to call the CCI-Resume and CCI-Suspend functions immediately after a CCI-Init function and before a CCI-Close function. However, for longer sessions, you may find that including several CCI-Resume and CCI-Suspend functions provides a more efficient application.
Note: There is a CCI-Resumeserver call embedded within CCI-Receiveall. A CCI-Resumeserver call should not, therefore, follow a CCI-Receiveall call.
For a client, the overall control area contains those functions which are used to initialize and close down the client. CCI-Initclient is used to initialize a connection to a specific service and to enable data to be transferred between two corresponding application segments. CCI-Closeclient is used to close down a client connection, following a CCI-Suspendclient function call.
For a server, the overall control area contains the functions used to initialize and close down the server and also those functions which enable data to be received and processed.
Server initialization necessitates several function calls. In a single server/single client connection the sequence of CCI-Initserver, CCI-Connect, CCI-Resume, and CCI-Receive is used. Alternatively, you can simply issue a CCI-Initserver function call followed by CCI-Receiveall.
CCI-Initserver registers the service with the network. CCI-Receiveall can be used to accept incoming connections from new CCI-Initclient calls being made to that server. CCI-Receiveall performs CCI-Resumes on all sessions and returns when data is received on a session connected to this server.
In this way, CCI-Receiveall saves time, particularly in multi-tasking environments such as UNIX and OS/2 where processes might be sharing processor time. A single call to CCI-Receiveall pauses the process until another call to that process is made, or until the call has timed-out.
When you use CCI-Receiveall, you should be aware of the following:
The basic design of a server must include instructions which:
Performed by issuing a CCImodule call where module corresponds to the communications protocol in use, for example, CCITCP.
CCI-Initserver initializes a server and advertises the fact that it is available on the network.
CCI-Connect establishes a connection between a server and a client. CCI-Resumeserver prepares a connection between a server and a client for use, and must be issued before data can be transferred.
The CCI-Receive function call accepts data/instructions.
This code implements the functionality of your server and is independent of CCI.
The CCI-Send function call sends data/instructions.
The server can loop to listen for new connections by issuing a CCI-Suspendserver on the current connection and then looping to the CCI-Connect call.
CCI-Suspendserver suspends a connection and must be issued before a CCI-Closeserver function call which terminates a server.
The corresponding client process must include instructions which:
Performed by issuing a CCImodule call where module corresponds to the communications protocol in use, for example, CCITCP.
CCI-Initclient intializes a client and establishes a connection between the client and a server.
The CCI-Send function call sends instructions/data.
The CCI-Receive function call accepts data.
This code implements the functionality of your client and is independent of CCI.
The client can continue to send and receive data by looping CCI-Send and CCI-Receive calls.
CCI-Suspendclient suspends a connection between a client and a server. CCI-Closeclient disconnects the client from the server.
For a single server/single client connection, the CCI functions are performed in the following sequence:
Server
|
Client
CCI-Initclient
|
In a single server/single client connection, the call to CCI-Connect ensures that only one client is allowed to connect. Once a connection is made, the server stops listening for other clients.
You can also connect the server with many clients, possibly at the same time, using the CCI functions shown below:
Server Client 1 Client 2 CCIprotocol CCI-Initserver CCI-Initclient CCI-Resumeclient CCI-Receiveall CCI-Send CCI-Send CCI-Receive CCI-Suspendserver CCI-Suspendclient CCI-Initclient CCI-Resumeclient CCI-Receiveall CCI-Send CCI-Send CCI-Receive CCI-Suspendserver CCI-Suspendclient CCI-Resumeclient CCI-Receiveall CCI-Send CCI-Send CCI-Receive CCI-Receive CCI-Send CCI-Send CCI-Receive CCI-Suspendserver CCI-Suspendclient CCI-Hangup CCI-Closeclient CCI-Hangup CCI-Closeclient CCI-Closeserver
The conversation is initiated at the server by initializing a CCI protocol support module and then calling CCI-Initserver followed by a call to CCI-Receiveall. This call connects with any client requesting a connection, and receives a message from any connected client. The server is not aware of a new connection until the client sends a message which is returned to the server by a CCI-Receiveall call.
Asynchronous CCI function calls enable you to use more than one communications protocol from a single application. This allows great flexibility in producing network applications that pass data to and from network endpoints using different network protocols.
You can start a service using one protocol (for example, TCP/IP using the CCITCP module), then switch to another (for example, named pipes using the CCINAMP module on OS/2 or the CCINAMPU module on UNIX) and start a service of the same name using the new protocol. You can use any number of protocols, provided that they are supported by your environment.
Switching protocols resets the Linkage Section of your application so that it points to the new protocol. The old protocol retains its own data areas so that you can switch back to it later if you want.
When switching protocols, you must remember the parameters that are specific to each protocol; that is, the srvrhandles, sessionids, async handles, data buffers, and so on.
Example
The following example shows you how to switch from CCITCP to CCINAMP on OS/2. (If you are running under UNIX, substitute CCINAMPU for all occurrences of CCINAMP.)
These instructions correspond to the following code. Note that in this example, only one linkage section record is required.
* Startup application server * initialize CCITCP call "CCITCP" call CCI-Initserver using servername serverhandle-TCP cciend call CCI-Receiveall using serverhandle-TCP sessionid-TCP buffer maxlen actuallen async-TCP-recvall cciend
* initialize named pipes support call "CCINAMP" call CCI-Initserver using servername serverhandle-NAMP cciend call CCI-Receiveall using serverhandle-NAMP sessionid-NAMP buffer maxlen actuallen async-NAMP-recvall cciend
* reset linkage section to TCP/IP support call "CCITCP" * act on received data if present call CCI-Query using async-TCP-recvall * reply, if needed here call CCI-Send using sessionid-TCP buffer sendlen async-TCP-send cciend call CCI-Suspendserver using sessionid-TCP * reset linkage section to named pipes support call "CCINAMP" call CCI-Query using async-NAMP-recvall . . .
So, in the above example, one service is registered on two network media with the same name. Either of these can be used by calling the relevant CCI function to select the correct protocol support module for use. You do not have to change the Initserver/Receiveall code if a single set of data is used for all the parameters and then stored away in the relevant area for the protocol concerned after the CCI functions are completed.
Further calls to each server and any sessions connected to each server simply require a call to the relevant CCI function to reset the linkage section table. Any or all functions are then available as if they were in a single protocol application.
By using procedure-pointers (function-pointers) to access CCI, you can re-use the transport code to gain access to several protocols without changing execution code.
The following example code makes an initialization call to the CCITCP module and then calls the CCI-Initclient function. This code is contained in the sample programs cciserv.cbl and ccicli.cbl in your cobol\demo directory on DOS, Windows and OS/2 and in the directory $COBDIR/demo/ccitcp on UNIX.
data division. working-storage section. 01 param-block. 03 signature. 05 CCISIGN pic x(6). 05 CCITYPE pic x(8). 05 CCIVERSN pic x(6). 03 table-pointer usage pointer.
01 srvrn pic x(8) value "server1". 01 machinename pic x(8) value spaces. 01 sessid pic x(4) comp-5. linkage section. copy "ccitab.cpy". 01 proctab. 03 CCI-Initserver procedure-pointer. 03 CCI-Closeserver procedure-pointer. 03 CCI-Initclient procedure-pointer. 03 CCI-Closeclient procedure-pointer. 03 CCI-Hangup procedure-pointer. 03 CCI-Send procedure-pointer. 03 CCI-Receive procedure-pointer. 03 CCI-Receiveall procedure-pointer. 03 CCI-Transact procedure-pointer. 03 CCI-Connect procedure-pointer. 03 CCI-Wait procedure-pointer. 03 CCI-Query procedure-pointer. 03 CCI-Resumeclient procedure-pointer. 03 CCI-Suspendclient procedure-pointer. 03 CCI-Resumeserver procedure-pointer. 03 CCI-Suspendserver procedure-pointer. 03 CCI-Geterror procedure-pointer. 03 CCI-Trace procedure-pointer. 03 CCI-Timeout procedure-pointer.
procedure division. call "CCITCP" using param-block if ccitype not = "TCP/IP" display "TCP/IP expected. CCITCP returned " ccitype stop run end-if set address of proctab to table-pointer call CCI-Initclient using srvrname machinename sessid async cciend.
Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names
used herein are protected by international law.
Introduction to Communications Programming | Common Communications Interface |