Question & Answer
Question
Calling unix-type APIs in ILE CL Program.
This document will use API QIBM_QTG_DEVINIT exit point as an example to illustrate the concept.
Cause
Additional search kwds: Sample Example CL CLP CLLE
Answer
When you call an API, the protocol for passing parameters is to typically pass a space pointer that points to the information being passed. (This is also referred to as pass-by-reference.) This is the convention used by default for the control language (CL), RPG, and COBOL compilers. Care must be used in those languages that support pass-by-value (such as ILE C) to ensure that these conventions are followed. Refer to the appropriate language documentation for instructions. The parameter passing convention of pass-by-reference can be used in all programming languages. Some of the UNIX-type APIs require pass-by-value parameter passing. VisualAge® C++ for IBM® i also supports pass-by-value parameter passing.
If you’ve used any of the ILE compilers, you probably know that IBM ships thousands of procedure-level APIs. Many of those procedures are defined to expect parameters to be passed “by value” and CL could only pass parameters “by reference”.
In V5R3, the CALLPRC command allows you to choose whether the parameter is passed by reference or by value.
•CALLPRC (Call Procedure) command supports calls from ILE CL procedures to other ILE procedures
•In prior releases, CALLPRC only supported passing parameters "by reference"
•Can specify *BYREF or *BYVAL special value for each parameter being passed
•Enables ILE CL to call many MI and C functions and other procedure APIs
•Maximum numbers of parameters still 300
•Added TYPE(*PTR) on DCL statement
•New %ADDRESS built-in to set pointer
•New %OFFSET built-in to set or retrieve the offset portion of pointer variable
•Added STG(*BASED) attribute on DCL statement
•Enables calling (or being called by) programs that have pointer parameters
•Makes many procedure APIs available to ILE CL
–Full record-level file I/O
–String functions
Some people would not expect CL and pointers to be used in the same sentence! This enhancement is part of the effort to make CL more API-friendly. The fact is that many APIs either expect parameters that are pointers or return arrays of information, which are most naturally navigated using pointers and based variables.
We added pointer support in V5R4, with the related support for based variables and built-in functions, %ADDRESS and %OFFSET, to manipulate pointer variables. While both the classic and ILE CL compilers will benefit from the addition of pointer support, the ILE CL compiler may have the advantage because this support will make many API procedures available that the classic CL compiler cannot take advantage of.
•Declaring a Pointer CL Variable
DCL &CHARVAR *CHAR LEN(10)
DCL &PTRVAR *PTR ADDRESS(&CHARVAR)
•Declaring a *BASED CL Variable
DCL &ENTRYPTR *PTR
DCL &CHARENTRY *CHAR 10 STG(*BASED) BASPTR(&ENTRYPTR)
•Declaring a *DEFINED Pointer CL Variable
DCL &CHARSTRUCT *CHAR LEN(48)
DCL &PTRVAR2 *PTR STG(*DEFINED) DEFVAR(&CHARSTRUCT 17)
Below is a sample CLLE program that illustrates how to capture the IP address of clients using Telnet to connect to IBM i server. This CLLE program is using QIBM_QTG_DEVINIT exit point.
Details about Device initialization exit program are provided in IBM Knowledge Center
The ip address is contained in Connection description information. It is 4-byte unsigned.
Required parameter group
1 User description information I/O Char(*)
2 Device description information I/O Char(*)
3 Connection description information Input Char(*)
4 Environment options Input Char(*)
5 Length of environment options Input Binary(4)
6 Allow connection Output Char(1)
7 Allow autosign-on Output Char(1)
IPv4 Client internet address
The IP address (or type structure) of the requesting client. An IP address is always provided to the exit point program. The IP address is specified in this field if the address is an IPv4 address. If the address is a pure IPv6 address, it is specified in the IPv6 Client internet address field, in which case this structure is set to all binary zeros. The layout of the field is as follows:
Name
|
Size
|
Description
|
Table 2. Client IP address layout | ||
sin_len | CHAR(1) | Size of the sockaddr_in structure |
sin_family | CHAR(1) | Protocol family IP (Version 4) is hex 02 |
sin_port | CHAR(2) | 16-bit unsigned port number |
sin_addr | CHAR(16) | 4-byte unsigned |
The inet_ntoa() function is used to translate an Internet address from a 32-bit IP address to dotted decimal format.
/* The information contained in this document has not been submitted */
/* to any formal tests and is distributed on an 'As is' basis */
/* without any warranty either expressed or implied. The use of this */
/* information or the implementation of any of these techniques is a */
/* customer responsibility and depends on the customer's ability to */
/* evaluate and integrate them into the customer's operation */
/* environment. While each item may have been reviewed by IBM */
/* for accuracy in a specific situation, there is no guarantee that the */
/* same or similar results will be obtained elsewhere. Customers */
/* attempting to adapt these techniques to their environments do so */
/* at their own risk. */
/* The information contained in this document has not been submitted */
/* to any formal tests and is distributed on an 'As is' basis */
/* without any warranty either expressed or implied. The use of this */
/* information or the implementation of any of these techniques is a */
/* customer responsibility and depends on the customer's ability to */
/* evaluate and integrate them into the customer's operation */
/* environment. While each item may have been reviewed by IBM */
/* for accuracy in a specific situation, there is no guarantee that the */
/* same or similar results will be obtained elsewhere. Customers */
/* attempting to adapt these techniques to their environments do so */
/* at their own risk. */
PGM PARM(&USRDESC &DEVDESC &CONDESC &ENVDAT &ENVLTH &ALLOW &AUTOSGN)
DCL VAR(&USRDESC) TYPE(*CHAR) LEN(44)
DCL VAR(&DEVDESC) TYPE(*CHAR) LEN(40)
DCL VAR(&CONDESC) TYPE(*CHAR) LEN(74)
DCL VAR(&ENVDAT) TYPE(*CHAR) LEN(1024)
DCL VAR(&ENVLTH ) TYPE(*CHAR) LEN(04)
DCL VAR(&ALLOW ) TYPE(*CHAR) LEN(01)
DCL VAR(&AUTOSGN) TYPE(*CHAR) LEN(01)
/* define pointer variables */
DCL VAR(&IADDR) TYPE(*UINT) LEN(4)
DCL VAR(&PADDR) TYPE(*PTR)
DCL VAR(&BADDR) TYPE(*CHAR) STG(*BASED) BASPTR(&PADDR) LEN(15)
/* define variables to perform scanning and trimming */
DCL VAR(&SPOS) TYPE(*UINT) LEN(2)
DCL VAR(&ZERO) TYPE(*CHAR) LEN(1) VALUE(X'00')
DCL VAR(&TIME) TYPE(*CHAR) LEN(9)
/* ip address is 4-byte unsigned starting offset 9 of the connection description */
CHGVAR VAR(&IADDR) VALUE(%BIN(&CONDESC 9 4))
/* inet_ntoa is UNIX-type API and requires pass-by-value parameter passing */
CALLPRC PRC('inet_ntoa') PARM((&IADDR *BYVAL)) RTNVAL(&PADDR)
/* Locate first blank char that might be present at the tail end of ipaddr */
/* There is a good chance the ip address may not be using all 15 positions */
/* i.e 9.5.10.20 <== the last 6 positions will contain nulls, which will display as */
/* block cursor(s) when &BADDR is passed into SNDPGMMSG. This is not desirable. */
/* The trailing blanks need to be trimmed off */
CHGVAR VAR(&SPOS) VALUE(%SCAN(&ZERO &BADDR))
CHGVAR VAR(&SPOS) VALUE(&SPOS - 1)
CHGVAR VAR(&BADDR) VALUE(%SST(&BADDR 1 &SPOS))
/* the Exit Point is invoked by QTVDEVICE job */
/* SNDPGMMSG will post the dotted ipaddr in the QTVDEVICE message queue */
RTVSYSVAL SYSVAL(QTIME) RTNVAR(&TIME)
CHGVAR VAR(&TIME) VALUE(%SST(&TIME 1 2) *TCAT ':' *TCAT %SST(&TIME 3 2) *TCAT +
':' *TCAT %SST(&TIME 5 2))
SNDPGMMSG MSG(&BADDR *TCAT ' Connected at ' *CAT &TIME)
/* At this point you may want to block or allow the connection. I am allowing it. */
CHGVAR VAR(&ALLOW) VALUE('1')
ENDPGM
CRTBNDCL PGM(<yourlib>/<your pgm>) SRCFILE(<your lib>/< your QCLLESRC>)
The program now needs to be added to Exit Point:-
ADDEXITPGM EXITPNT(QIBM_QTG_DEVINIT) FORMAT(INIT0100)
PGMNBR(1) PGM(<yourlib>/<yourpgm>) REPLACE(*YES)
CRTEXITPNT(*NO) PGMDTA(*JOB *CALC 10)
Exit point performance
The Telnet server response time for your initial session request includes any time that it takes for the server to call, process, and return the QIBM_QTG_DEVINIT exit program. If your exit program is doing significant processing, the performance impact might result in a longer wait before your session is established. If you want to modify the default 60 second timeout value for user exit programs, you can use the ADDEXITPGM command to add user data that is read as the timeout value. In the above example, the PGMDTA parameter overrides the default 60 second timeout to 10 seconds.
Any new Telnet connection that is requested will result in the exit point program to get control.
Was this topic helpful?
Document Information
More support for:
IBM i
Software version:
Version Independent
Operating system(s):
IBM i
Document number:
687873
Modified date:
24 March 2024
UID
nas8N1022435