quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

os400sys.c (23348B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  *
     24  ***************************************************************************/
     25 
     26 /* OS/400 additional support. */
     27 
     28 #include <curl/curl.h>
     29 #include "config-os400.h"  /* Not curl_setup.h: we only need some defines. */
     30 
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 #include <sys/un.h>
     34 
     35 #include <stdlib.h>
     36 #include <stddef.h>
     37 #include <string.h>
     38 #include <pthread.h>
     39 #include <netdb.h>
     40 #include <qadrt.h>
     41 #include <errno.h>
     42 
     43 #ifdef HAVE_LIBZ
     44 #include <zlib.h>
     45 #endif
     46 
     47 #ifdef HAVE_GSSAPI
     48 #include <gssapi.h>
     49 #endif
     50 
     51 #ifndef CURL_DISABLE_LDAP
     52 #include <ldap.h>
     53 #endif
     54 
     55 #include <netinet/in.h>
     56 #include <arpa/inet.h>
     57 
     58 #include "os400sys.h"
     59 
     60 /**
     61 *** QADRT OS/400 ASCII runtime defines only the most used procedures, but a
     62 *** lot of them are not supported. This module implements ASCII wrappers for
     63 *** those that are used by libcurl, but not defined by QADRT.
     64 **/
     65 
     66 #pragma convert(0)                              /* Restore EBCDIC. */
     67 
     68 #define MIN_BYTE_GAIN   1024    /* Minimum gain when shortening a buffer. */
     69 
     70 struct buffer_t {
     71   unsigned long size;            /* Buffer size. */
     72   char *buf;                     /* Buffer address. */
     73 };
     74 
     75 
     76 static char *buffer_undef(localkey_t key, long size);
     77 static char *buffer_threaded(localkey_t key, long size);
     78 static char *buffer_unthreaded(localkey_t key, long size);
     79 
     80 static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
     81 static pthread_key_t    thdkey;
     82 static struct buffer_t *locbufs;
     83 
     84 char *(*Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
     85 
     86 static void thdbufdestroy(void *private)
     87 {
     88   if(private) {
     89     struct buffer_t *p = (struct buffer_t *) private;
     90     localkey_t i;
     91 
     92     for(i = (localkey_t) 0; i < LK_LAST; i++) {
     93       free(p->buf);
     94       p++;
     95     }
     96 
     97     free(private);
     98   }
     99 }
    100 
    101 
    102 static void
    103 terminate(void)
    104 {
    105   if(Curl_thread_buffer == buffer_threaded) {
    106     locbufs = pthread_getspecific(thdkey);
    107     pthread_setspecific(thdkey, (void *) NULL);
    108     pthread_key_delete(thdkey);
    109   }
    110 
    111   if(Curl_thread_buffer != buffer_undef) {
    112     thdbufdestroy((void *) locbufs);
    113     locbufs = (struct buffer_t *) NULL;
    114   }
    115 
    116   Curl_thread_buffer = buffer_undef;
    117 }
    118 
    119 
    120 static char *
    121 get_buffer(struct buffer_t *buf, long size)
    122 {
    123   char *cp;
    124 
    125   /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long.
    126      Return the buffer address. */
    127 
    128   if(size < 0)
    129     return buf->buf;
    130 
    131   if(!buf->buf) {
    132     buf->buf = malloc(size);
    133     if(buf->buf)
    134       buf->size = size;
    135 
    136     return buf->buf;
    137   }
    138 
    139   if((unsigned long) size <= buf->size) {
    140     /* Shorten the buffer only if it frees a significant byte count. This
    141        avoids some realloc() overhead. */
    142 
    143     if(buf->size - size < MIN_BYTE_GAIN)
    144       return buf->buf;
    145   }
    146 
    147   /* Resize the buffer. */
    148 
    149   cp = realloc(buf->buf, size);
    150   if(cp) {
    151     buf->buf = cp;
    152     buf->size = size;
    153   }
    154   else if(size <= buf->size)
    155     cp = buf->buf;
    156 
    157   return cp;
    158 }
    159 
    160 
    161 static char *
    162 buffer_unthreaded(localkey_t key, long size)
    163 {
    164   return get_buffer(locbufs + key, size);
    165 }
    166 
    167 
    168 static char *
    169 buffer_threaded(localkey_t key, long size)
    170 {
    171   struct buffer_t *bufs;
    172 
    173   /* Get the buffer for the given local key in the current thread, and
    174      make sure it is at least `size'-byte long. Set `size' to < 0 to get
    175      its address only. */
    176 
    177   bufs = (struct buffer_t *) pthread_getspecific(thdkey);
    178 
    179   if(!bufs) {
    180     if(size < 0)
    181       return (char *) NULL;             /* No buffer yet. */
    182 
    183     /* Allocate buffer descriptors for the current thread. */
    184 
    185     bufs = calloc((size_t) LK_LAST, sizeof(*bufs));
    186     if(!bufs)
    187       return (char *) NULL;
    188 
    189     if(pthread_setspecific(thdkey, (void *) bufs)) {
    190       free(bufs);
    191       return (char *) NULL;
    192     }
    193   }
    194 
    195   return get_buffer(bufs + key, size);
    196 }
    197 
    198 
    199 static char *
    200 buffer_undef(localkey_t key, long size)
    201 {
    202   /* Define the buffer system, get the buffer for the given local key in
    203      the current thread, and make sure it is at least `size'-byte long.
    204      Set `size' to < 0 to get its address only. */
    205 
    206   pthread_mutex_lock(&mutex);
    207 
    208   /* Determine if we can use pthread-specific data. */
    209 
    210   if(Curl_thread_buffer == buffer_undef) {      /* If unchanged during lock. */
    211     if(!pthread_key_create(&thdkey, thdbufdestroy))
    212       Curl_thread_buffer = buffer_threaded;
    213     else {
    214       locbufs = calloc((size_t) LK_LAST, sizeof(*locbufs));
    215       if(!locbufs) {
    216         pthread_mutex_unlock(&mutex);
    217         return (char *) NULL;
    218       }
    219       else
    220         Curl_thread_buffer = buffer_unthreaded;
    221     }
    222 
    223     atexit(terminate);
    224   }
    225 
    226   pthread_mutex_unlock(&mutex);
    227   return Curl_thread_buffer(key, size);
    228 }
    229 
    230 
    231 static char *
    232 set_thread_string(localkey_t key, const char *s)
    233 {
    234   int i;
    235   char *cp;
    236 
    237   if(!s)
    238     return (char *) NULL;
    239 
    240   i = strlen(s) + 1;
    241   cp = Curl_thread_buffer(key, MAX_CONV_EXPANSION * i + 1);
    242 
    243   if(cp) {
    244     i = QadrtConvertE2A(cp, s, MAX_CONV_EXPANSION * i, i);
    245     cp[i] = '\0';
    246   }
    247 
    248   return cp;
    249 }
    250 
    251 
    252 int
    253 Curl_getnameinfo_a(const struct sockaddr *sa, socklen_t salen,
    254                    char *nodename, socklen_t nodenamelen,
    255                    char *servname, socklen_t servnamelen,
    256                    int flags)
    257 {
    258   char *enodename = NULL;
    259   char *eservname = NULL;
    260   int status;
    261 
    262   if(nodename && nodenamelen) {
    263     enodename = malloc(nodenamelen);
    264     if(!enodename)
    265       return EAI_MEMORY;
    266   }
    267 
    268   if(servname && servnamelen) {
    269     eservname = malloc(servnamelen);
    270     if(!eservname) {
    271       free(enodename);
    272       return EAI_MEMORY;
    273     }
    274   }
    275 
    276   status = getnameinfo(sa, salen, enodename, nodenamelen,
    277                        eservname, servnamelen, flags);
    278 
    279   if(!status) {
    280     int i;
    281     if(enodename) {
    282       i = QadrtConvertE2A(nodename, enodename,
    283                           nodenamelen - 1, strlen(enodename));
    284       nodename[i] = '\0';
    285     }
    286 
    287     if(eservname) {
    288       i = QadrtConvertE2A(servname, eservname,
    289                           servnamelen - 1, strlen(eservname));
    290       servname[i] = '\0';
    291     }
    292   }
    293 
    294   free(enodename);
    295   free(eservname);
    296   return status;
    297 }
    298 
    299 int
    300 Curl_getaddrinfo_a(const char *nodename, const char *servname,
    301                    const struct addrinfo *hints,
    302                    struct addrinfo **res)
    303 {
    304   char *enodename;
    305   char *eservname;
    306   int status;
    307   int i;
    308 
    309   enodename = (char *) NULL;
    310   eservname = (char *) NULL;
    311 
    312   if(nodename) {
    313     i = strlen(nodename);
    314 
    315     enodename = malloc(i + 1);
    316     if(!enodename)
    317       return EAI_MEMORY;
    318 
    319     i = QadrtConvertA2E(enodename, nodename, i, i);
    320     enodename[i] = '\0';
    321   }
    322 
    323   if(servname) {
    324     i = strlen(servname);
    325 
    326     eservname = malloc(i + 1);
    327     if(!eservname) {
    328       free(enodename);
    329       return EAI_MEMORY;
    330     }
    331 
    332     QadrtConvertA2E(eservname, servname, i, i);
    333     eservname[i] = '\0';
    334   }
    335 
    336   status = getaddrinfo(enodename, eservname, hints, res);
    337   free(enodename);
    338   free(eservname);
    339   return status;
    340 }
    341 
    342 #ifdef HAVE_GSSAPI
    343 
    344 /* ASCII wrappers for the GSSAPI procedures. */
    345 
    346 static int
    347 Curl_gss_convert_in_place(OM_uint32 *minor_status, gss_buffer_t buf)
    348 {
    349   unsigned int i = buf->length;
    350 
    351   /* Convert `buf' in place, from EBCDIC to ASCII.
    352      If error, release the buffer and return -1. Else return 0. */
    353 
    354   if(i) {
    355     char *t = malloc(i);
    356     if(!t) {
    357       gss_release_buffer(minor_status, buf);
    358 
    359       if(minor_status)
    360         /* !checksrc! disable ERRNOVAR 1 */
    361         *minor_status = ENOMEM;
    362 
    363       return -1;
    364     }
    365 
    366     QadrtConvertE2A(t, buf->value, i, i);
    367     memcpy(buf->value, t, i);
    368     free(t);
    369   }
    370 
    371   return 0;
    372 }
    373 
    374 
    375 OM_uint32
    376 Curl_gss_import_name_a(OM_uint32 *minor_status, gss_buffer_t in_name,
    377                        gss_OID in_name_type, gss_name_t *out_name)
    378 {
    379   OM_uint32 rc;
    380   unsigned int i;
    381   gss_buffer_desc in;
    382 
    383   if(!in_name || !in_name->value || !in_name->length)
    384     return gss_import_name(minor_status, in_name, in_name_type, out_name);
    385 
    386   memcpy((char *) &in, (char *) in_name, sizeof(in));
    387   i = in.length;
    388 
    389   in.value = malloc(i + 1);
    390   if(!in.value) {
    391     if(minor_status)
    392       /* !checksrc! disable ERRNOVAR 1 */
    393       *minor_status = ENOMEM;
    394 
    395     return GSS_S_FAILURE;
    396   }
    397 
    398   QadrtConvertA2E(in.value, in_name->value, i, i);
    399   ((char *) in.value)[i] = '\0';
    400   rc = gss_import_name(minor_status, &in, in_name_type, out_name);
    401   free(in.value);
    402   return rc;
    403 }
    404 
    405 OM_uint32
    406 Curl_gss_display_status_a(OM_uint32 *minor_status, OM_uint32 status_value,
    407                           int status_type, gss_OID mech_type,
    408                           gss_msg_ctx_t *message_context,
    409                           gss_buffer_t status_string)
    410 {
    411   int rc;
    412 
    413   rc = gss_display_status(minor_status, status_value, status_type,
    414                           mech_type, message_context, status_string);
    415 
    416   if(rc != GSS_S_COMPLETE || !status_string ||
    417      !status_string->length || !status_string->value)
    418     return rc;
    419 
    420   /* No way to allocate a buffer here, because it will be released by
    421      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
    422      with ASCII to return it. */
    423 
    424   if(Curl_gss_convert_in_place(minor_status, status_string))
    425     return GSS_S_FAILURE;
    426 
    427   return rc;
    428 }
    429 
    430 OM_uint32
    431 Curl_gss_init_sec_context_a(OM_uint32 *minor_status,
    432                             gss_cred_id_t cred_handle,
    433                             gss_ctx_id_t *context_handle,
    434                             gss_name_t target_name, gss_OID mech_type,
    435                             gss_flags_t req_flags, OM_uint32 time_req,
    436                             gss_channel_bindings_t input_chan_bindings,
    437                             gss_buffer_t input_token,
    438                             gss_OID *actual_mech_type,
    439                             gss_buffer_t output_token, gss_flags_t *ret_flags,
    440                             OM_uint32 *time_rec)
    441 {
    442   int rc;
    443   gss_buffer_desc in;
    444   gss_buffer_t inp;
    445 
    446   in.value = NULL;
    447   inp = input_token;
    448 
    449   if(inp) {
    450     if(inp->length && inp->value) {
    451       unsigned int i = inp->length;
    452 
    453       in.value = malloc(i + 1);
    454       if(!in.value) {
    455         if(minor_status)
    456           /* !checksrc! disable ERRNOVAR 1 */
    457           *minor_status = ENOMEM;
    458 
    459         return GSS_S_FAILURE;
    460       }
    461 
    462       QadrtConvertA2E(in.value, input_token->value, i, i);
    463       ((char *) in.value)[i] = '\0';
    464       in.length = i;
    465       inp = &in;
    466     }
    467   }
    468 
    469   rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
    470                             target_name, mech_type, req_flags, time_req,
    471                             input_chan_bindings, inp, actual_mech_type,
    472                             output_token, ret_flags, time_rec);
    473   free(in.value);
    474 
    475   if(rc != GSS_S_COMPLETE || !output_token ||
    476      !output_token->length || !output_token->value)
    477     return rc;
    478 
    479   /* No way to allocate a buffer here, because it will be released by
    480      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
    481      with ASCII to return it. */
    482 
    483   if(Curl_gss_convert_in_place(minor_status, output_token))
    484     return GSS_S_FAILURE;
    485 
    486   return rc;
    487 }
    488 
    489 
    490 OM_uint32
    491 Curl_gss_delete_sec_context_a(OM_uint32 *minor_status,
    492                               gss_ctx_id_t *context_handle,
    493                               gss_buffer_t output_token)
    494 {
    495   OM_uint32 rc;
    496 
    497   rc = gss_delete_sec_context(minor_status, context_handle, output_token);
    498 
    499   if(rc != GSS_S_COMPLETE || !output_token ||
    500      !output_token->length || !output_token->value)
    501     return rc;
    502 
    503   /* No way to allocate a buffer here, because it will be released by
    504      gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
    505      with ASCII to return it. */
    506 
    507   if(Curl_gss_convert_in_place(minor_status, output_token))
    508     return GSS_S_FAILURE;
    509 
    510   return rc;
    511 }
    512 
    513 #endif /* HAVE_GSSAPI */
    514 
    515 #ifndef CURL_DISABLE_LDAP
    516 
    517 /* ASCII wrappers for the LDAP procedures. */
    518 
    519 void *
    520 Curl_ldap_init_a(char *host, int port)
    521 {
    522   size_t i;
    523   char *ehost;
    524   void *result;
    525 
    526   if(!host)
    527     return (void *) ldap_init(host, port);
    528 
    529   i = strlen(host);
    530 
    531   ehost = malloc(i + 1);
    532   if(!ehost)
    533     return (void *) NULL;
    534 
    535   QadrtConvertA2E(ehost, host, i, i);
    536   ehost[i] = '\0';
    537   result = (void *) ldap_init(ehost, port);
    538   free(ehost);
    539   return result;
    540 }
    541 
    542 int
    543 Curl_ldap_simple_bind_s_a(void *ld, char *dn, char *passwd)
    544 {
    545   int i;
    546   char *edn;
    547   char *epasswd;
    548 
    549   edn = (char *) NULL;
    550   epasswd = (char *) NULL;
    551 
    552   if(dn) {
    553     i = strlen(dn);
    554 
    555     edn = malloc(i + 1);
    556     if(!edn)
    557       return LDAP_NO_MEMORY;
    558 
    559     QadrtConvertA2E(edn, dn, i, i);
    560     edn[i] = '\0';
    561   }
    562 
    563   if(passwd) {
    564     i = strlen(passwd);
    565 
    566     epasswd = malloc(i + 1);
    567     if(!epasswd) {
    568       free(edn);
    569       return LDAP_NO_MEMORY;
    570     }
    571 
    572     QadrtConvertA2E(epasswd, passwd, i, i);
    573     epasswd[i] = '\0';
    574   }
    575 
    576   i = ldap_simple_bind_s(ld, edn, epasswd);
    577   free(epasswd);
    578   free(edn);
    579   return i;
    580 }
    581 
    582 int
    583 Curl_ldap_search_s_a(void *ld, char *base, int scope, char *filter,
    584                      char **attrs, int attrsonly, LDAPMessage **res)
    585 {
    586   int i;
    587   int j;
    588   char *ebase;
    589   char *efilter;
    590   char **eattrs;
    591   int status;
    592 
    593   ebase = (char *) NULL;
    594   efilter = (char *) NULL;
    595   eattrs = (char **) NULL;
    596   status = LDAP_SUCCESS;
    597 
    598   if(base) {
    599     i = strlen(base);
    600 
    601     ebase = malloc(i + 1);
    602     if(!ebase)
    603       status = LDAP_NO_MEMORY;
    604     else {
    605       QadrtConvertA2E(ebase, base, i, i);
    606       ebase[i] = '\0';
    607     }
    608   }
    609 
    610   if(filter && status == LDAP_SUCCESS) {
    611     i = strlen(filter);
    612 
    613     efilter = malloc(i + 1);
    614     if(!efilter)
    615       status = LDAP_NO_MEMORY;
    616     else {
    617       QadrtConvertA2E(efilter, filter, i, i);
    618       efilter[i] = '\0';
    619     }
    620   }
    621 
    622   if(attrs && status == LDAP_SUCCESS) {
    623     for(i = 0; attrs[i++];)
    624       ;
    625 
    626     eattrs = calloc(i, sizeof(*eattrs));
    627     if(!eattrs)
    628       status = LDAP_NO_MEMORY;
    629     else {
    630       for(j = 0; attrs[j]; j++) {
    631         i = strlen(attrs[j]);
    632 
    633         eattrs[j] = malloc(i + 1);
    634         if(!eattrs[j]) {
    635           status = LDAP_NO_MEMORY;
    636           break;
    637         }
    638 
    639         QadrtConvertA2E(eattrs[j], attrs[j], i, i);
    640         eattrs[j][i] = '\0';
    641       }
    642     }
    643   }
    644 
    645   if(status == LDAP_SUCCESS)
    646     status = ldap_search_s(ld, ebase ? ebase : "", scope,
    647                            efilter ? efilter : "(objectclass=*)",
    648                            eattrs, attrsonly, res);
    649 
    650   if(eattrs) {
    651     for(j = 0; eattrs[j]; j++)
    652       free(eattrs[j]);
    653 
    654     free(eattrs);
    655   }
    656 
    657   free(efilter);
    658   free(ebase);
    659   return status;
    660 }
    661 
    662 
    663 struct berval **
    664 Curl_ldap_get_values_len_a(void *ld, LDAPMessage *entry, const char *attr)
    665 {
    666   char *cp;
    667   struct berval **result;
    668 
    669   cp = (char *) NULL;
    670 
    671   if(attr) {
    672     int i = strlen(attr);
    673 
    674     cp = malloc(i + 1);
    675     if(!cp) {
    676       ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
    677                        ldap_err2string(LDAP_NO_MEMORY));
    678       return (struct berval **) NULL;
    679     }
    680 
    681     QadrtConvertA2E(cp, attr, i, i);
    682     cp[i] = '\0';
    683   }
    684 
    685   result = ldap_get_values_len(ld, entry, cp);
    686   free(cp);
    687 
    688   /* Result data are binary in nature, so they haven't been
    689      converted to EBCDIC. Therefore do not convert. */
    690 
    691   return result;
    692 }
    693 
    694 char *
    695 Curl_ldap_err2string_a(int error)
    696 {
    697   return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error));
    698 }
    699 
    700 char *
    701 Curl_ldap_get_dn_a(void *ld, LDAPMessage *entry)
    702 {
    703   int i;
    704   char *cp;
    705   char *cp2;
    706 
    707   cp = ldap_get_dn(ld, entry);
    708 
    709   if(!cp)
    710     return cp;
    711 
    712   i = strlen(cp);
    713 
    714   cp2 = malloc(i + 1);
    715   if(!cp2)
    716     return cp2;
    717 
    718   QadrtConvertE2A(cp2, cp, i, i);
    719   cp2[i] = '\0';
    720 
    721   /* No way to allocate a buffer here, because it will be released by
    722      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
    723      overwrite the EBCDIC buffer with ASCII to return it. */
    724 
    725   strcpy(cp, cp2);
    726   free(cp2);
    727   return cp;
    728 }
    729 
    730 char *
    731 Curl_ldap_first_attribute_a(void *ld,
    732                             LDAPMessage *entry, BerElement **berptr)
    733 {
    734   int i;
    735   char *cp;
    736   char *cp2;
    737 
    738   cp = ldap_first_attribute(ld, entry, berptr);
    739 
    740   if(!cp)
    741     return cp;
    742 
    743   i = strlen(cp);
    744 
    745   cp2 = malloc(i + 1);
    746   if(!cp2)
    747     return cp2;
    748 
    749   QadrtConvertE2A(cp2, cp, i, i);
    750   cp2[i] = '\0';
    751 
    752   /* No way to allocate a buffer here, because it will be released by
    753      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
    754      overwrite the EBCDIC buffer with ASCII to return it. */
    755 
    756   strcpy(cp, cp2);
    757   free(cp2);
    758   return cp;
    759 }
    760 
    761 char *
    762 Curl_ldap_next_attribute_a(void *ld,
    763                            LDAPMessage *entry, BerElement *berptr)
    764 {
    765   int i;
    766   char *cp;
    767   char *cp2;
    768 
    769   cp = ldap_next_attribute(ld, entry, berptr);
    770 
    771   if(!cp)
    772     return cp;
    773 
    774   i = strlen(cp);
    775 
    776   cp2 = malloc(i + 1);
    777   if(!cp2)
    778     return cp2;
    779 
    780   QadrtConvertE2A(cp2, cp, i, i);
    781   cp2[i] = '\0';
    782 
    783   /* No way to allocate a buffer here, because it will be released by
    784      ldap_memfree() and ldap_memalloc() does not exist. The solution is to
    785      overwrite the EBCDIC buffer with ASCII to return it. */
    786 
    787   strcpy(cp, cp2);
    788   free(cp2);
    789   return cp;
    790 }
    791 
    792 #endif /* CURL_DISABLE_LDAP */
    793 
    794 static int
    795 sockaddr2ebcdic(struct sockaddr_storage *dstaddr,
    796                 const struct sockaddr *srcaddr, int srclen)
    797 {
    798   const struct sockaddr_un *srcu;
    799   struct sockaddr_un *dstu;
    800   unsigned int i;
    801   unsigned int dstsize;
    802 
    803   /* Convert a socket address to job CCSID, if needed. */
    804 
    805   if(!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
    806      sizeof(srcaddr->sa_family) || srclen > sizeof(*dstaddr)) {
    807     /* !checksrc! disable ERRNOVAR 1 */
    808     errno = EINVAL;
    809     return -1;
    810   }
    811 
    812   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
    813 
    814   switch(srcaddr->sa_family) {
    815 
    816   case AF_UNIX:
    817     srcu = (const struct sockaddr_un *) srcaddr;
    818     dstu = (struct sockaddr_un *) dstaddr;
    819     dstsize = sizeof(*dstaddr) - offsetof(struct sockaddr_un, sun_path);
    820     srclen -= offsetof(struct sockaddr_un, sun_path);
    821     i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
    822     dstu->sun_path[i] = '\0';
    823     srclen = i + offsetof(struct sockaddr_un, sun_path);
    824   }
    825 
    826   return srclen;
    827 }
    828 
    829 
    830 static int
    831 sockaddr2ascii(struct sockaddr *dstaddr, int dstlen,
    832                const struct sockaddr_storage *srcaddr, int srclen)
    833 {
    834   const struct sockaddr_un *srcu;
    835   struct sockaddr_un *dstu;
    836   unsigned int dstsize;
    837 
    838   /* Convert a socket address to ASCII, if needed. */
    839 
    840   if(!srclen)
    841     return 0;
    842   if(srclen > dstlen)
    843     srclen = dstlen;
    844   if(!srcaddr || srclen < 0) {
    845     /* !checksrc! disable ERRNOVAR 1 */
    846     errno = EINVAL;
    847     return -1;
    848   }
    849 
    850   memcpy((char *) dstaddr, (char *) srcaddr, srclen);
    851 
    852   if(srclen >= offsetof(struct sockaddr_storage, ss_family) +
    853      sizeof(srcaddr->ss_family)) {
    854     switch(srcaddr->ss_family) {
    855 
    856     case AF_UNIX:
    857       srcu = (const struct sockaddr_un *) srcaddr;
    858       dstu = (struct sockaddr_un *) dstaddr;
    859       dstsize = dstlen - offsetof(struct sockaddr_un, sun_path);
    860       srclen -= offsetof(struct sockaddr_un, sun_path);
    861       if(dstsize > 0 && srclen > 0) {
    862         srclen = QadrtConvertE2A(dstu->sun_path, srcu->sun_path,
    863                                  dstsize - 1, srclen);
    864         dstu->sun_path[srclen] = '\0';
    865       }
    866       srclen += offsetof(struct sockaddr_un, sun_path);
    867     }
    868   }
    869 
    870   return srclen;
    871 }
    872 
    873 int
    874 Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen)
    875 {
    876   int i;
    877   struct sockaddr_storage laddr;
    878 
    879   i = sockaddr2ebcdic(&laddr, destaddr, addrlen);
    880 
    881   if(i < 0)
    882     return -1;
    883 
    884   return connect(sd, (struct sockaddr *) &laddr, i);
    885 }
    886 
    887 int
    888 Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen)
    889 {
    890   int i;
    891   struct sockaddr_storage laddr;
    892 
    893   i = sockaddr2ebcdic(&laddr, localaddr, addrlen);
    894 
    895   if(i < 0)
    896     return -1;
    897 
    898   return bind(sd, (struct sockaddr *) &laddr, i);
    899 }
    900 
    901 int
    902 Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
    903                   const struct sockaddr *dstaddr, int addrlen)
    904 {
    905   int i;
    906   struct sockaddr_storage laddr;
    907 
    908   i = sockaddr2ebcdic(&laddr, dstaddr, addrlen);
    909 
    910   if(i < 0)
    911     return -1;
    912 
    913   return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
    914 }
    915 
    916 int
    917 Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
    918                     struct sockaddr *fromaddr, int *addrlen)
    919 {
    920   int rcvlen;
    921   struct sockaddr_storage laddr;
    922   int laddrlen = sizeof(laddr);
    923 
    924   if(!fromaddr || !addrlen || *addrlen <= 0)
    925     return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
    926 
    927   laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
    928   rcvlen = recvfrom(sd, buffer, buflen, flags,
    929                     (struct sockaddr *) &laddr, &laddrlen);
    930 
    931   if(rcvlen < 0)
    932     return rcvlen;
    933 
    934   if(laddr.ss_family == AF_UNSPEC)
    935     laddrlen = 0;
    936   else {
    937     laddrlen = sockaddr2ascii(fromaddr, *addrlen, &laddr, laddrlen);
    938     if(laddrlen < 0)
    939       return laddrlen;
    940   }
    941   *addrlen = laddrlen;
    942   return rcvlen;
    943 }
    944 
    945 int
    946 Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen)
    947 {
    948   struct sockaddr_storage laddr;
    949   int laddrlen = sizeof(laddr);
    950   int retcode = getpeername(sd, (struct sockaddr *) &laddr, &laddrlen);
    951 
    952   if(!retcode) {
    953     laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
    954     if(laddrlen < 0)
    955       return laddrlen;
    956     *addrlen = laddrlen;
    957   }
    958 
    959   return retcode;
    960 }
    961 
    962 int
    963 Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen)
    964 {
    965   struct sockaddr_storage laddr;
    966   int laddrlen = sizeof(laddr);
    967   int retcode = getsockname(sd, (struct sockaddr *) &laddr, &laddrlen);
    968 
    969   if(!retcode) {
    970     laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
    971     if(laddrlen < 0)
    972       return laddrlen;
    973     *addrlen = laddrlen;
    974   }
    975 
    976   return retcode;
    977 }
    978 
    979 
    980 #ifdef HAVE_LIBZ
    981 const char *
    982 Curl_os400_zlibVersion(void)
    983 {
    984   return set_thread_string(LK_ZLIB_VERSION, zlibVersion());
    985 }
    986 
    987 
    988 int
    989 Curl_os400_inflateInit_(z_streamp strm, const char *version, int stream_size)
    990 {
    991   z_const char *msgb4 = strm->msg;
    992   int ret;
    993 
    994   ret = inflateInit(strm);
    995 
    996   if(strm->msg != msgb4)
    997     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
    998 
    999   return ret;
   1000 }
   1001 
   1002 int
   1003 Curl_os400_inflateInit2_(z_streamp strm, int windowBits,
   1004                          const char *version, int stream_size)
   1005 {
   1006   z_const char *msgb4 = strm->msg;
   1007   int ret;
   1008 
   1009   ret = inflateInit2(strm, windowBits);
   1010 
   1011   if(strm->msg != msgb4)
   1012     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
   1013 
   1014   return ret;
   1015 }
   1016 
   1017 int
   1018 Curl_os400_inflate(z_streamp strm, int flush)
   1019 {
   1020   z_const char *msgb4 = strm->msg;
   1021   int ret;
   1022 
   1023   ret = inflate(strm, flush);
   1024 
   1025   if(strm->msg != msgb4)
   1026     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
   1027 
   1028   return ret;
   1029 }
   1030 
   1031 int
   1032 Curl_os400_inflateEnd(z_streamp strm)
   1033 {
   1034   z_const char *msgb4 = strm->msg;
   1035   int ret;
   1036 
   1037   ret = inflateEnd(strm);
   1038 
   1039   if(strm->msg != msgb4)
   1040     strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
   1041 
   1042   return ret;
   1043 }
   1044 
   1045 #endif