| xf.li | 6c8fc1e | 2023-08-12 00:11:09 -0700 | [diff] [blame] | 1 |  | 
|  | 2 | Implementation notes: | 
|  | 3 |  | 
|  | 4 | This is a true OS/400 implementation, not a PASE implementation (for PASE, | 
|  | 5 | use AIX implementation). | 
|  | 6 |  | 
|  | 7 | The biggest problem with OS/400 is EBCDIC. Libcurl implements an internal | 
|  | 8 | conversion mechanism, but it has been designed for computers that have a | 
|  | 9 | single native character set. OS/400 default native character set varies | 
|  | 10 | depending on the country for which it has been localized. And more, a job | 
|  | 11 | may dynamically alter its "native" character set. | 
|  | 12 | Several characters that do not have fixed code in EBCDIC variants are | 
|  | 13 | used in libcurl strings. As a consequence, using the existing conversion | 
|  | 14 | mechanism would have lead in a localized binary library - not portable across | 
|  | 15 | countries. | 
|  | 16 | For this reason, and because libcurl was originally designed for ASCII based | 
|  | 17 | operating systems, the current OS/400 implementation uses ASCII as internal | 
|  | 18 | character set. This has been accomplished using the QADRT library and | 
|  | 19 | include files, a C and system procedures ASCII wrapper library. See IBM QADRT | 
|  | 20 | description for more information. | 
|  | 21 | This then results in libcurl being an ASCII library: any function string | 
|  | 22 | argument is taken/returned in ASCII and a C/C++ calling program built around | 
|  | 23 | QADRT may use libcurl functions as on any other platform. | 
|  | 24 | QADRT does not define ASCII wrappers for all C/system procedures: the | 
|  | 25 | OS/400 configuration header file and an additional module (os400sys.c) define | 
|  | 26 | some more of them, that are used by libcurl and that QADRT left out. | 
|  | 27 | To support all the different variants of EBCDIC, non-standard wrapper | 
|  | 28 | procedures have been added to libcurl on OS/400: they provide an additional | 
|  | 29 | CCSID (numeric Coded Character Set ID specific to OS/400) parameter for each | 
|  | 30 | string argument. Callback procedures arguments giving access to strings are | 
|  | 31 | NOT converted, so text gathered this way is (probably !) ASCII. | 
|  | 32 |  | 
|  | 33 | Another OS/400 problem comes from the fact that the last fixed argument of a | 
|  | 34 | vararg procedure may not be of type char, unsigned char, short or unsigned | 
|  | 35 | short. Enums that are internally implemented by the C compiler as one of these | 
|  | 36 | types are also forbidden. Libcurl uses enums as vararg procedure tagfields... | 
|  | 37 | Happily, there is a pragma forcing enums to type "int". The original libcurl | 
|  | 38 | header files are thus altered during build process to use this pragma, in | 
|  | 39 | order to force libcurl enums of being type int (the pragma disposition in use | 
|  | 40 | before inclusion is restored before resuming the including unit compilation). | 
|  | 41 |  | 
|  | 42 | Secure socket layer is provided by the IBM GSKit API: unlike other SSL | 
|  | 43 | implementations, GSKit is based on "certificate stores" or keyrings | 
|  | 44 | rather than individual certificate/key files. Certificate stores, as well as | 
|  | 45 | "certificate labels" are managed by external IBM-defined applications. | 
|  | 46 | There are two ways to specify an SSL context: | 
|  | 47 | - By an application identifier. | 
|  | 48 | - By a keyring file pathname and (optionally) certificate label. | 
|  | 49 | To identify an SSL context by application identifier, use option | 
|  | 50 | SETOPT_SSLCERT to specify the application identifier. | 
|  | 51 | To address an SSL context by keyring and certificate label, use CURLOPT_CAINFO | 
|  | 52 | to set-up the keyring pathname, CURLOPT_SSLCERT to define the certificate label | 
|  | 53 | (omitting it will cause the default certificate in keyring to be used) and | 
|  | 54 | CURLOPT_KEYPASSWD to give the keyring password. If SSL is used without | 
|  | 55 | defining any of these options, the default (i.e.: system) keyring is used for | 
|  | 56 | server certificate validation. | 
|  | 57 |  | 
|  | 58 | Non-standard EBCDIC wrapper prototypes are defined in an additional header | 
|  | 59 | file: ccsidcurl.h. These should be self-explanatory to an OS/400-aware | 
|  | 60 | designer. CCSID 0 can be used to select the current job's CCSID. | 
|  | 61 | Wrapper procedures with variable arguments are described below: | 
|  | 62 |  | 
|  | 63 | _ curl_easy_setopt_ccsid() | 
|  | 64 | Variable arguments are a string pointer and a CCSID (unsigned int) for | 
|  | 65 | options: | 
|  | 66 | CURLOPT_ABSTRACT_UNIX_SOCKET | 
|  | 67 | CURLOPT_ALTSVC | 
|  | 68 | CURLOPT_AWS_SIGV4 | 
|  | 69 | CURLOPT_CAINFO | 
|  | 70 | CURLOPT_CAPATH | 
|  | 71 | CURLOPT_COOKIE | 
|  | 72 | CURLOPT_COOKIEFILE | 
|  | 73 | CURLOPT_COOKIEJAR | 
|  | 74 | CURLOPT_COOKIELIST | 
|  | 75 | CURLOPT_COPYPOSTFIELDS | 
|  | 76 | CURLOPT_CRLFILE | 
|  | 77 | CURLOPT_CUSTOMREQUEST | 
|  | 78 | CURLOPT_DEFAULT_PROTOCOL | 
|  | 79 | CURLOPT_DNS_SERVERS | 
|  | 80 | CURLOPT_DOH_URL | 
|  | 81 | CURLOPT_EGDSOCKET | 
|  | 82 | CURLOPT_ENCODING | 
|  | 83 | CURLOPT_FTPPORT | 
|  | 84 | CURLOPT_FTP_ACCOUNT | 
|  | 85 | CURLOPT_FTP_ALTERNATIVE_TO_USER | 
|  | 86 | CURLOPT_HSTS | 
|  | 87 | CURLOPT_INTERFACE | 
|  | 88 | CURLOPT_ISSUERCERT | 
|  | 89 | CURLOPT_KEYPASSWD | 
|  | 90 | CURLOPT_KRBLEVEL | 
|  | 91 | CURLOPT_LOGIN_OPTIONS | 
|  | 92 | CURLOPT_MAIL_AUTH | 
|  | 93 | CURLOPT_MAIL_FROM | 
|  | 94 | CURLOPT_NETRC_FILE | 
|  | 95 | CURLOPT_NOPROXY | 
|  | 96 | CURLOPT_PASSWORD | 
|  | 97 | CURLOPT_PINNEDPUBLICKEY | 
|  | 98 | CURLOPT_PRE_PROXY | 
|  | 99 | CURLOPT_PROXY | 
|  | 100 | CURLOPT_PROXYPASSWORD | 
|  | 101 | CURLOPT_PROXYUSERNAME | 
|  | 102 | CURLOPT_PROXYUSERPWD | 
|  | 103 | CURLOPT_PROXY_CAINFO | 
|  | 104 | CURLOPT_PROXY_CAPATH | 
|  | 105 | CURLOPT_PROXY_CRLFILE | 
|  | 106 | CURLOPT_PROXY_KEYPASSWD | 
|  | 107 | CURLOPT_PROXY_PINNEDPUBLICKEY | 
|  | 108 | CURLOPT_PROXY_SERVICE_NAME | 
|  | 109 | CURLOPT_PROXY_SSLCERT | 
|  | 110 | CURLOPT_PROXY_SSLCERTTYPE | 
|  | 111 | CURLOPT_PROXY_SSLKEY | 
|  | 112 | CURLOPT_PROXY_SSLKEYTYPE | 
|  | 113 | CURLOPT_PROXY_SSL_CIPHER_LIST | 
|  | 114 | CURLOPT_PROXY_TLS13_CIPHERS | 
|  | 115 | CURLOPT_PROXY_TLSAUTH_PASSWORD | 
|  | 116 | CURLOPT_PROXY_TLSAUTH_TYPE | 
|  | 117 | CURLOPT_PROXY_TLSAUTH_USERNAME | 
|  | 118 | CURLOPT_RANDOM_FILE | 
|  | 119 | CURLOPT_RANGE | 
|  | 120 | CURLOPT_REFERER | 
|  | 121 | CURLOPT_REQUEST_TARGET | 
|  | 122 | CURLOPT_RTSP_SESSION_UID | 
|  | 123 | CURLOPT_RTSP_STREAM_URI | 
|  | 124 | CURLOPT_RTSP_TRANSPORT | 
|  | 125 | CURLOPT_SASL_AUTHZID | 
|  | 126 | CURLOPT_SERVICE_NAME | 
|  | 127 | CURLOPT_SOCKS5_GSSAPI_SERVICE | 
|  | 128 | CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 | 
|  | 129 | CURLOPT_SSH_KNOWNHOSTS | 
|  | 130 | CURLOPT_SSH_PRIVATE_KEYFILE | 
|  | 131 | CURLOPT_SSH_PUBLIC_KEYFILE | 
|  | 132 | CURLOPT_SSLCERT | 
|  | 133 | CURLOPT_SSLCERTTYPE | 
|  | 134 | CURLOPT_SSLENGINE | 
|  | 135 | CURLOPT_SSLKEY | 
|  | 136 | CURLOPT_SSLKEYTYPE | 
|  | 137 | CURLOPT_SSL_CIPHER_LIST | 
|  | 138 | CURLOPT_TLS13_CIPHERS | 
|  | 139 | CURLOPT_TLSAUTH_PASSWORD | 
|  | 140 | CURLOPT_TLSAUTH_TYPE | 
|  | 141 | CURLOPT_TLSAUTH_USERNAME | 
|  | 142 | CURLOPT_UNIX_SOCKET_PATH | 
|  | 143 | CURLOPT_URL | 
|  | 144 | CURLOPT_USERAGENT | 
|  | 145 | CURLOPT_USERNAME | 
|  | 146 | CURLOPT_USERPWD | 
|  | 147 | CURLOPT_XOAUTH2_BEARER | 
|  | 148 | Else it is the same as for curl_easy_setopt(). | 
|  | 149 | Note that CURLOPT_ERRORBUFFER is not in the list above, since it gives the | 
|  | 150 | address of an (empty) character buffer, not the address of a string. | 
|  | 151 | CURLOPT_POSTFIELDS stores the address of static binary data (of type void *) and | 
|  | 152 | thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after | 
|  | 153 | CURLOPT_POSTFIELDSIZE != -1, the data size is adjusted according to the | 
|  | 154 | CCSID conversion result length. | 
|  | 155 |  | 
|  | 156 | _ curl_formadd_ccsid() | 
|  | 157 | In the variable argument list, string pointers should be followed by a (long) | 
|  | 158 | CCSID for the following options: | 
|  | 159 | CURLFORM_FILENAME | 
|  | 160 | CURLFORM_CONTENTTYPE | 
|  | 161 | CURLFORM_BUFFER | 
|  | 162 | CURLFORM_FILE | 
|  | 163 | CURLFORM_FILECONTENT | 
|  | 164 | CURLFORM_COPYCONTENTS | 
|  | 165 | CURLFORM_COPYNAME | 
|  | 166 | CURLFORM_PTRNAME | 
|  | 167 | If taken from an argument array, an additional array entry must follow each | 
|  | 168 | entry containing one of the above option. This additional entry holds the CCSID | 
|  | 169 | in its value field, and the option field is meaningless. | 
|  | 170 | It is not possible to have a string pointer and its CCSID across a function | 
|  | 171 | parameter/array boundary. | 
|  | 172 | Please note that CURLFORM_PTRCONTENTS and CURLFORM_BUFFERPTR are considered | 
|  | 173 | unconvertible strings and thus are NOT followed by a CCSID. | 
|  | 174 |  | 
|  | 175 | _ curl_easy_getinfo_ccsid() | 
|  | 176 | The following options are followed by a 'char * *' and a CCSID. Unlike | 
|  | 177 | curl_easy_getinfo(), the value returned in the pointer should be released with | 
|  | 178 | curl_free() after use: | 
|  | 179 | CURLINFO_EFFECTIVE_URL | 
|  | 180 | CURLINFO_CONTENT_TYPE | 
|  | 181 | CURLINFO_FTP_ENTRY_PATH | 
|  | 182 | CURLINFO_REDIRECT_URL | 
|  | 183 | CURLINFO_REFERER | 
|  | 184 | CURLINFO_PRIMARY_IP | 
|  | 185 | CURLINFO_RTSP_SESSION_ID | 
|  | 186 | CURLINFO_LOCAL_IP | 
|  | 187 | CURLINFO_SCHEME | 
|  | 188 | Likewise, the following options are followed by a struct curl_slist * * and a | 
|  | 189 | CCSID. | 
|  | 190 | CURLINFO_SSL_ENGINES | 
|  | 191 | CURLINFO_COOKIELIST | 
|  | 192 | Lists returned should be released with curl_slist_free_all() after use. | 
|  | 193 | Option CURLINFO_CERTINFO is followed by a struct curl_certinfo * * and a | 
|  | 194 | CCSID. Returned structures should be freed with curl_certinfo_free_all() | 
|  | 195 | after use. | 
|  | 196 | Other options are processed like in curl_easy_getinfo(). | 
|  | 197 |  | 
|  | 198 | _ curl_pushheader_bynum_cssid() and curl_pushheader_byname_ccsid() | 
|  | 199 | Although the prototypes are self-explanatory, the returned string pointer | 
|  | 200 | should be released with curl_free() after use, as opposite to the non-ccsid | 
|  | 201 | versions of these procedures. | 
|  | 202 | Please note that HTTP2 is not (yet) implemented on OS/400, thus these | 
|  | 203 | functions will always return NULL. | 
|  | 204 |  | 
|  | 205 | _ curl_easy_option_by_name_ccsid() returns a pointer to an untranslated option | 
|  | 206 | metadata structure. As each curl_easyoption structure holds the option name in | 
|  | 207 | ASCII, the curl_easy_option_get_name_ccsid() function allows getting it in any | 
|  | 208 | supported ccsid. However the caller should release the returned pointer with | 
|  | 209 | curl_free() after use. | 
|  | 210 |  | 
|  | 211 |  | 
|  | 212 | Standard compilation environment does support neither autotools nor make; | 
|  | 213 | in fact, very few common utilities are available. As a consequence, the | 
|  | 214 | config-os400.h has been coded manually and the compilation scripts are | 
|  | 215 | a set of shell scripts stored in subdirectory packages/OS400. | 
|  | 216 |  | 
|  | 217 | The "curl" command and the test environment are currently not supported on | 
|  | 218 | OS/400. | 
|  | 219 |  | 
|  | 220 |  | 
|  | 221 | Protocols currently implemented on OS/400: | 
|  | 222 | _ DICT | 
|  | 223 | _ FILE | 
|  | 224 | _ FTP | 
|  | 225 | _ FTPS | 
|  | 226 | _ FTP with secure transmission | 
|  | 227 | _ GOPHER | 
|  | 228 | _ HTTP | 
|  | 229 | _ HTTPS | 
|  | 230 | _ IMAP | 
|  | 231 | _ IMAPS | 
|  | 232 | _ IMAP with secure transmission | 
|  | 233 | _ LDAP | 
|  | 234 | _ POP3 | 
|  | 235 | _ POP3S | 
|  | 236 | _ POP3 with secure transmission | 
|  | 237 | _ RTSP | 
|  | 238 | _ SCP if libssh2 is enabled | 
|  | 239 | _ SFTP if libssh2 is enabled | 
|  | 240 | _ SMTP | 
|  | 241 | _ SMTPS | 
|  | 242 | _ SMTP with secure transmission | 
|  | 243 | _ TELNET | 
|  | 244 | _ TFTP | 
|  | 245 |  | 
|  | 246 |  | 
|  | 247 |  | 
|  | 248 | Compiling on OS/400: | 
|  | 249 |  | 
|  | 250 | These instructions targets people who knows about OS/400, compiling, IFS and | 
|  | 251 | archive extraction. Do not ask questions about these subjects if you're not | 
|  | 252 | familiar with. | 
|  | 253 |  | 
|  | 254 | _ As a prerequisite, QADRT development environment must be installed. | 
|  | 255 | For more information on downloading and installing the QADRT development kit, | 
|  | 256 | please see https://www.ibm.com/support/pages/node/6258183 | 
|  | 257 | _ If data compression has to be supported, ZLIB development environment must | 
|  | 258 | be installed. | 
|  | 259 | _ Likewise, if SCP and SFTP protocols have to be compiled in, LIBSSH2 | 
|  | 260 | developent environment must be installed. | 
|  | 261 | _ Install the curl source directory in IFS. Do NOT install it in the | 
|  | 262 | installation target directory (which defaults to /curl). | 
|  | 263 | _ Enter Qshell (QSH, not PASE) | 
|  | 264 | _ Change current directory to the curl installation directory | 
|  | 265 | _ Change current directory to ./packages/OS400 | 
|  | 266 | _ Edit file iniscript.sh. You may want to change tunable configuration | 
|  | 267 | parameters, like debug info generation, optimization level, listing option, | 
|  | 268 | target library, ZLIB/LIBSSH2 availability and location, etc. | 
|  | 269 | _ Copy any file in the current directory to makelog (i.e.: | 
|  | 270 | cp initscript.sh makelog): this is intended to create the makelog file with | 
|  | 271 | an ASCII CCSID! | 
|  | 272 | _ Enter the command "sh makefile.sh > makelog 2>&1" | 
|  | 273 | _ Examine the makelog file to check for compilation errors. | 
|  | 274 |  | 
|  | 275 | Leaving file initscript.sh unchanged, this will produce the following OS/400 | 
|  | 276 | objects: | 
|  | 277 | _ Library CURL. All other objects will be stored in this library. | 
|  | 278 | _ Modules for all libcurl units. | 
|  | 279 | _ Binding directory CURL_A, to be used at calling program link time for | 
|  | 280 | statically binding the modules (specify BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR) | 
|  | 281 | when creating a program using CURL_A). | 
|  | 282 | _ Service program CURL.<soname>, where <soname> is extracted from the | 
|  | 283 | lib/Makefile.am VERSION variable. To be used at calling program run-time | 
|  | 284 | when this program has dynamically bound curl at link time. | 
|  | 285 | _ Binding directory CURL. To be used to dynamically bind libcurl when linking a | 
|  | 286 | calling program. | 
|  | 287 | _ Source file H. It contains all the include members needed to compile a C/C++ | 
|  | 288 | module using libcurl, and an ILE/RPG /copy member for support in this | 
|  | 289 | language. | 
|  | 290 | _ Standard C/C++ libcurl include members in file H. | 
|  | 291 | _ CCSIDCURL member in file H. This defines the non-standard EBCDIC wrappers for | 
|  | 292 | C and C++. | 
|  | 293 | _ CURL.INC member in file H. This defines everything needed by an ILE/RPG | 
|  | 294 | program using libcurl. | 
|  | 295 | _ LIBxxx modules and programs. Although the test environment is not supported | 
|  | 296 | on OS/400, the libcurl test programs are compiled for manual tests. | 
|  | 297 | _ IFS directory /curl/include/curl containing the C header files for IFS source | 
|  | 298 | C/C++ compilation and curl.inc.rpgle for IFS source ILE/RPG compilation. | 
|  | 299 |  | 
|  | 300 |  | 
|  | 301 |  | 
|  | 302 | Special programming consideration: | 
|  | 303 |  | 
|  | 304 | QADRT being used, the following points must be considered: | 
|  | 305 | _ If static binding is used, service program QADRTTS must be linked too. | 
|  | 306 | _ The EBCDIC CCSID used by QADRT is 37 by default, NOT THE JOB'S CCSID. If | 
|  | 307 | another EBCDIC CCSID is required, it must be set via a locale through a call | 
|  | 308 | to setlocale_a (QADRT's setlocale() ASCII wrapper) with category LC_ALL or | 
|  | 309 | LC_CTYPE, or by setting environment variable QADRT_ENV_LOCALE to the locale | 
|  | 310 | object path before executing the program. | 
|  | 311 | _ Do not use original source include files unless you know what you are doing. | 
|  | 312 | Use the installed members instead (in /QSYS.LIB/CURL.LIB/H.FILE and | 
|  | 313 | /curl/include/curl). | 
|  | 314 |  | 
|  | 315 |  | 
|  | 316 |  | 
|  | 317 | ILE/RPG support: | 
|  | 318 |  | 
|  | 319 | Since 95% of the OS/400 programmers use ILE/RPG exclusively, a definition | 
|  | 320 | /INCLUDE member is provided for this language. To include all libcurl | 
|  | 321 | definitions in an ILE/RPG module, line | 
|  | 322 |  | 
|  | 323 | h bnddir('CURL/CURL') | 
|  | 324 |  | 
|  | 325 | must figure in the program header, and line | 
|  | 326 |  | 
|  | 327 | d/include curl/h,curl.inc | 
|  | 328 |  | 
|  | 329 | in the global data section of the module's source code. | 
|  | 330 |  | 
|  | 331 | No vararg procedure support exists in ILE/RPG: for this reason, the following | 
|  | 332 | considerations apply: | 
|  | 333 | _ Procedures curl_easy_setopt_long(), curl_easy_setopt_object(), | 
|  | 334 | curl_easy_setopt_function() and curl_easy_setopt_offset() are all alias | 
|  | 335 | prototypes to curl_easy_setopt(), but with different parameter lists. | 
|  | 336 | _ Procedures curl_easy_getinfo_string(), curl_easy_getinfo_long(), | 
|  | 337 | curl_easy_getinfo_double(), curl_easy_getinfo_slist(), | 
|  | 338 | curl_easy_getinfo_ptr(), curl_easy_getinfo_socket() and | 
|  | 339 | curl_easy_getinfo_off_t() are all alias prototypes to curl_easy_getinfo(), | 
|  | 340 | but with different parameter lists. | 
|  | 341 | _ Procedures curl_multi_setopt_long(), curl_multi_setopt_object(), | 
|  | 342 | curl_multi_setopt_function() and curl_multi_setopt_offset() are all alias | 
|  | 343 | prototypes to curl_multi_setopt(), but with different parameter lists. | 
|  | 344 | _ The prototype of procedure curl_formadd() allows specifying a pointer option | 
|  | 345 | and the CURLFORM_END option. This makes possible to use an option array | 
|  | 346 | without any additional definition. If some specific incompatible argument | 
|  | 347 | list is used in the ILE/RPG program, the latter must define a specialised | 
|  | 348 | alias. The same applies to curl_formadd_ccsid() too. | 
|  | 349 |  | 
|  | 350 | Since RPG cannot cast a long to a pointer, procedure curl_form_long_value() | 
|  | 351 | is provided for that purpose: this allows storing a long value in the curl_forms | 
|  | 352 | array. |