xref: /third_party/curl/packages/OS400/os400sys.c (revision 13498266)
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
70struct buffer_t {
71  unsigned long size;            /* Buffer size. */
72  char *buf;                     /* Buffer address. */
73};
74
75
76static char *buffer_undef(localkey_t key, long size);
77static char *buffer_threaded(localkey_t key, long size);
78static char *buffer_unthreaded(localkey_t key, long size);
79
80static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
81static pthread_key_t    thdkey;
82static struct buffer_t *locbufs;
83
84char *(*Curl_thread_buffer)(localkey_t key, long size) = buffer_undef;
85
86static 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
102static void
103terminate(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
120static char *
121get_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
161static char *
162buffer_unthreaded(localkey_t key, long size)
163{
164  return get_buffer(locbufs + key, size);
165}
166
167
168static char *
169buffer_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
199static char *
200buffer_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
231static char *
232set_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
252int
253Curl_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
299int
300Curl_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
346static int
347Curl_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        *minor_status = ENOMEM;
361
362      return -1;
363    }
364
365    QadrtConvertE2A(t, buf->value, i, i);
366    memcpy(buf->value, t, i);
367    free(t);
368  }
369
370  return 0;
371}
372
373
374OM_uint32
375Curl_gss_import_name_a(OM_uint32 *minor_status, gss_buffer_t in_name,
376                       gss_OID in_name_type, gss_name_t *out_name)
377{
378  OM_uint32 rc;
379  unsigned int i;
380  gss_buffer_desc in;
381
382  if(!in_name || !in_name->value || !in_name->length)
383    return gss_import_name(minor_status, in_name, in_name_type, out_name);
384
385  memcpy((char *) &in, (char *) in_name, sizeof(in));
386  i = in.length;
387
388  in.value = malloc(i + 1);
389  if(!in.value) {
390    if(minor_status)
391      *minor_status = ENOMEM;
392
393    return GSS_S_FAILURE;
394  }
395
396  QadrtConvertA2E(in.value, in_name->value, i, i);
397  ((char *) in.value)[i] = '\0';
398  rc = gss_import_name(minor_status, &in, in_name_type, out_name);
399  free(in.value);
400  return rc;
401}
402
403OM_uint32
404Curl_gss_display_status_a(OM_uint32 *minor_status, OM_uint32 status_value,
405                          int status_type, gss_OID mech_type,
406                          gss_msg_ctx_t *message_context,
407                          gss_buffer_t status_string)
408{
409  int rc;
410
411  rc = gss_display_status(minor_status, status_value, status_type,
412                          mech_type, message_context, status_string);
413
414  if(rc != GSS_S_COMPLETE || !status_string ||
415     !status_string->length || !status_string->value)
416    return rc;
417
418  /* No way to allocate a buffer here, because it will be released by
419     gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
420     with ASCII to return it. */
421
422  if(Curl_gss_convert_in_place(minor_status, status_string))
423    return GSS_S_FAILURE;
424
425  return rc;
426}
427
428OM_uint32
429Curl_gss_init_sec_context_a(OM_uint32 *minor_status,
430                            gss_cred_id_t cred_handle,
431                            gss_ctx_id_t *context_handle,
432                            gss_name_t target_name, gss_OID mech_type,
433                            gss_flags_t req_flags, OM_uint32 time_req,
434                            gss_channel_bindings_t input_chan_bindings,
435                            gss_buffer_t input_token,
436                            gss_OID *actual_mech_type,
437                            gss_buffer_t output_token, gss_flags_t *ret_flags,
438                            OM_uint32 *time_rec)
439{
440  int rc;
441  gss_buffer_desc in;
442  gss_buffer_t inp;
443
444  in.value = NULL;
445  inp = input_token;
446
447  if(inp) {
448    if(inp->length && inp->value) {
449      unsigned int i = inp->length;
450
451      in.value = malloc(i + 1);
452      if(!in.value) {
453        if(minor_status)
454          *minor_status = ENOMEM;
455
456        return GSS_S_FAILURE;
457      }
458
459      QadrtConvertA2E(in.value, input_token->value, i, i);
460      ((char *) in.value)[i] = '\0';
461      in.length = i;
462      inp = &in;
463    }
464  }
465
466  rc = gss_init_sec_context(minor_status, cred_handle, context_handle,
467                            target_name, mech_type, req_flags, time_req,
468                            input_chan_bindings, inp, actual_mech_type,
469                            output_token, ret_flags, time_rec);
470  free(in.value);
471
472  if(rc != GSS_S_COMPLETE || !output_token ||
473     !output_token->length || !output_token->value)
474    return rc;
475
476  /* No way to allocate a buffer here, because it will be released by
477     gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
478     with ASCII to return it. */
479
480  if(Curl_gss_convert_in_place(minor_status, output_token))
481    return GSS_S_FAILURE;
482
483  return rc;
484}
485
486
487OM_uint32
488Curl_gss_delete_sec_context_a(OM_uint32 *minor_status,
489                              gss_ctx_id_t *context_handle,
490                              gss_buffer_t output_token)
491{
492  OM_uint32 rc;
493
494  rc = gss_delete_sec_context(minor_status, context_handle, output_token);
495
496  if(rc != GSS_S_COMPLETE || !output_token ||
497     !output_token->length || !output_token->value)
498    return rc;
499
500  /* No way to allocate a buffer here, because it will be released by
501     gss_release_buffer(). The solution is to overwrite the EBCDIC buffer
502     with ASCII to return it. */
503
504  if(Curl_gss_convert_in_place(minor_status, output_token))
505    return GSS_S_FAILURE;
506
507  return rc;
508}
509
510#endif /* HAVE_GSSAPI */
511
512#ifndef CURL_DISABLE_LDAP
513
514/* ASCII wrappers for the LDAP procedures. */
515
516void *
517Curl_ldap_init_a(char *host, int port)
518{
519  size_t i;
520  char *ehost;
521  void *result;
522
523  if(!host)
524    return (void *) ldap_init(host, port);
525
526  i = strlen(host);
527
528  ehost = malloc(i + 1);
529  if(!ehost)
530    return (void *) NULL;
531
532  QadrtConvertA2E(ehost, host, i, i);
533  ehost[i] = '\0';
534  result = (void *) ldap_init(ehost, port);
535  free(ehost);
536  return result;
537}
538
539int
540Curl_ldap_simple_bind_s_a(void *ld, char *dn, char *passwd)
541{
542  int i;
543  char *edn;
544  char *epasswd;
545
546  edn = (char *) NULL;
547  epasswd = (char *) NULL;
548
549  if(dn) {
550    i = strlen(dn);
551
552    edn = malloc(i + 1);
553    if(!edn)
554      return LDAP_NO_MEMORY;
555
556    QadrtConvertA2E(edn, dn, i, i);
557    edn[i] = '\0';
558  }
559
560  if(passwd) {
561    i = strlen(passwd);
562
563    epasswd = malloc(i + 1);
564    if(!epasswd) {
565      free(edn);
566      return LDAP_NO_MEMORY;
567    }
568
569    QadrtConvertA2E(epasswd, passwd, i, i);
570    epasswd[i] = '\0';
571  }
572
573  i = ldap_simple_bind_s(ld, edn, epasswd);
574  free(epasswd);
575  free(edn);
576  return i;
577}
578
579int
580Curl_ldap_search_s_a(void *ld, char *base, int scope, char *filter,
581                     char **attrs, int attrsonly, LDAPMessage **res)
582{
583  int i;
584  int j;
585  char *ebase;
586  char *efilter;
587  char **eattrs;
588  int status;
589
590  ebase = (char *) NULL;
591  efilter = (char *) NULL;
592  eattrs = (char **) NULL;
593  status = LDAP_SUCCESS;
594
595  if(base) {
596    i = strlen(base);
597
598    ebase = malloc(i + 1);
599    if(!ebase)
600      status = LDAP_NO_MEMORY;
601    else {
602      QadrtConvertA2E(ebase, base, i, i);
603      ebase[i] = '\0';
604    }
605  }
606
607  if(filter && status == LDAP_SUCCESS) {
608    i = strlen(filter);
609
610    efilter = malloc(i + 1);
611    if(!efilter)
612      status = LDAP_NO_MEMORY;
613    else {
614      QadrtConvertA2E(efilter, filter, i, i);
615      efilter[i] = '\0';
616    }
617  }
618
619  if(attrs && status == LDAP_SUCCESS) {
620    for(i = 0; attrs[i++];)
621      ;
622
623    eattrs = calloc(i, sizeof(*eattrs));
624    if(!eattrs)
625      status = LDAP_NO_MEMORY;
626    else {
627      for(j = 0; attrs[j]; j++) {
628        i = strlen(attrs[j]);
629
630        eattrs[j] = malloc(i + 1);
631        if(!eattrs[j]) {
632          status = LDAP_NO_MEMORY;
633          break;
634        }
635
636        QadrtConvertA2E(eattrs[j], attrs[j], i, i);
637        eattrs[j][i] = '\0';
638      }
639    }
640  }
641
642  if(status == LDAP_SUCCESS)
643    status = ldap_search_s(ld, ebase? ebase: "", scope,
644                           efilter? efilter: "(objectclass=*)",
645                           eattrs, attrsonly, res);
646
647  if(eattrs) {
648    for(j = 0; eattrs[j]; j++)
649      free(eattrs[j]);
650
651    free(eattrs);
652  }
653
654  free(efilter);
655  free(ebase);
656  return status;
657}
658
659
660struct berval **
661Curl_ldap_get_values_len_a(void *ld, LDAPMessage *entry, const char *attr)
662{
663  char *cp;
664  struct berval **result;
665
666  cp = (char *) NULL;
667
668  if(attr) {
669    int i = strlen(attr);
670
671    cp = malloc(i + 1);
672    if(!cp) {
673      ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL,
674                       ldap_err2string(LDAP_NO_MEMORY));
675      return (struct berval **) NULL;
676    }
677
678    QadrtConvertA2E(cp, attr, i, i);
679    cp[i] = '\0';
680  }
681
682  result = ldap_get_values_len(ld, entry, cp);
683  free(cp);
684
685  /* Result data are binary in nature, so they haven't been
686     converted to EBCDIC. Therefore do not convert. */
687
688  return result;
689}
690
691char *
692Curl_ldap_err2string_a(int error)
693{
694  return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error));
695}
696
697char *
698Curl_ldap_get_dn_a(void *ld, LDAPMessage *entry)
699{
700  int i;
701  char *cp;
702  char *cp2;
703
704  cp = ldap_get_dn(ld, entry);
705
706  if(!cp)
707    return cp;
708
709  i = strlen(cp);
710
711  cp2 = malloc(i + 1);
712  if(!cp2)
713    return cp2;
714
715  QadrtConvertE2A(cp2, cp, i, i);
716  cp2[i] = '\0';
717
718  /* No way to allocate a buffer here, because it will be released by
719     ldap_memfree() and ldap_memalloc() does not exist. The solution is to
720     overwrite the EBCDIC buffer with ASCII to return it. */
721
722  strcpy(cp, cp2);
723  free(cp2);
724  return cp;
725}
726
727char *
728Curl_ldap_first_attribute_a(void *ld,
729                            LDAPMessage *entry, BerElement **berptr)
730{
731  int i;
732  char *cp;
733  char *cp2;
734
735  cp = ldap_first_attribute(ld, entry, berptr);
736
737  if(!cp)
738    return cp;
739
740  i = strlen(cp);
741
742  cp2 = malloc(i + 1);
743  if(!cp2)
744    return cp2;
745
746  QadrtConvertE2A(cp2, cp, i, i);
747  cp2[i] = '\0';
748
749  /* No way to allocate a buffer here, because it will be released by
750     ldap_memfree() and ldap_memalloc() does not exist. The solution is to
751     overwrite the EBCDIC buffer with ASCII to return it. */
752
753  strcpy(cp, cp2);
754  free(cp2);
755  return cp;
756}
757
758char *
759Curl_ldap_next_attribute_a(void *ld,
760                           LDAPMessage *entry, BerElement *berptr)
761{
762  int i;
763  char *cp;
764  char *cp2;
765
766  cp = ldap_next_attribute(ld, entry, berptr);
767
768  if(!cp)
769    return cp;
770
771  i = strlen(cp);
772
773  cp2 = malloc(i + 1);
774  if(!cp2)
775    return cp2;
776
777  QadrtConvertE2A(cp2, cp, i, i);
778  cp2[i] = '\0';
779
780  /* No way to allocate a buffer here, because it will be released by
781     ldap_memfree() and ldap_memalloc() does not exist. The solution is to
782     overwrite the EBCDIC buffer with ASCII to return it. */
783
784  strcpy(cp, cp2);
785  free(cp2);
786  return cp;
787}
788
789#endif /* CURL_DISABLE_LDAP */
790
791static int
792sockaddr2ebcdic(struct sockaddr_storage *dstaddr,
793                const struct sockaddr *srcaddr, int srclen)
794{
795  const struct sockaddr_un *srcu;
796  struct sockaddr_un *dstu;
797  unsigned int i;
798  unsigned int dstsize;
799
800  /* Convert a socket address to job CCSID, if needed. */
801
802  if(!srcaddr || srclen < offsetof(struct sockaddr, sa_family) +
803     sizeof(srcaddr->sa_family) || srclen > sizeof(*dstaddr)) {
804    errno = EINVAL;
805    return -1;
806  }
807
808  memcpy((char *) dstaddr, (char *) srcaddr, srclen);
809
810  switch(srcaddr->sa_family) {
811
812  case AF_UNIX:
813    srcu = (const struct sockaddr_un *) srcaddr;
814    dstu = (struct sockaddr_un *) dstaddr;
815    dstsize = sizeof(*dstaddr) - offsetof(struct sockaddr_un, sun_path);
816    srclen -= offsetof(struct sockaddr_un, sun_path);
817    i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen);
818    dstu->sun_path[i] = '\0';
819    srclen = i + offsetof(struct sockaddr_un, sun_path);
820  }
821
822  return srclen;
823}
824
825
826static int
827sockaddr2ascii(struct sockaddr *dstaddr, int dstlen,
828               const struct sockaddr_storage *srcaddr, int srclen)
829{
830  const struct sockaddr_un *srcu;
831  struct sockaddr_un *dstu;
832  unsigned int dstsize;
833
834  /* Convert a socket address to ASCII, if needed. */
835
836  if(!srclen)
837    return 0;
838  if(srclen > dstlen)
839    srclen = dstlen;
840  if(!srcaddr || srclen < 0) {
841    errno = EINVAL;
842    return -1;
843  }
844
845  memcpy((char *) dstaddr, (char *) srcaddr, srclen);
846
847  if(srclen >= offsetof(struct sockaddr_storage, ss_family) +
848     sizeof(srcaddr->ss_family)) {
849    switch(srcaddr->ss_family) {
850
851    case AF_UNIX:
852      srcu = (const struct sockaddr_un *) srcaddr;
853      dstu = (struct sockaddr_un *) dstaddr;
854      dstsize = dstlen - offsetof(struct sockaddr_un, sun_path);
855      srclen -= offsetof(struct sockaddr_un, sun_path);
856      if(dstsize > 0 && srclen > 0) {
857        srclen = QadrtConvertE2A(dstu->sun_path, srcu->sun_path,
858                                 dstsize - 1, srclen);
859        dstu->sun_path[srclen] = '\0';
860      }
861      srclen += offsetof(struct sockaddr_un, sun_path);
862    }
863  }
864
865  return srclen;
866}
867
868int
869Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen)
870{
871  int i;
872  struct sockaddr_storage laddr;
873
874  i = sockaddr2ebcdic(&laddr, destaddr, addrlen);
875
876  if(i < 0)
877    return -1;
878
879  return connect(sd, (struct sockaddr *) &laddr, i);
880}
881
882int
883Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen)
884{
885  int i;
886  struct sockaddr_storage laddr;
887
888  i = sockaddr2ebcdic(&laddr, localaddr, addrlen);
889
890  if(i < 0)
891    return -1;
892
893  return bind(sd, (struct sockaddr *) &laddr, i);
894}
895
896int
897Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
898                  const struct sockaddr *dstaddr, int addrlen)
899{
900  int i;
901  struct sockaddr_storage laddr;
902
903  i = sockaddr2ebcdic(&laddr, dstaddr, addrlen);
904
905  if(i < 0)
906    return -1;
907
908  return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i);
909}
910
911int
912Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
913                    struct sockaddr *fromaddr, int *addrlen)
914{
915  int rcvlen;
916  struct sockaddr_storage laddr;
917  int laddrlen = sizeof(laddr);
918
919  if(!fromaddr || !addrlen || *addrlen <= 0)
920    return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen);
921
922  laddr.ss_family = AF_UNSPEC;          /* To detect if unused. */
923  rcvlen = recvfrom(sd, buffer, buflen, flags,
924                    (struct sockaddr *) &laddr, &laddrlen);
925
926  if(rcvlen < 0)
927    return rcvlen;
928
929  if(laddr.ss_family == AF_UNSPEC)
930    laddrlen = 0;
931  else {
932    laddrlen = sockaddr2ascii(fromaddr, *addrlen, &laddr, laddrlen);
933    if(laddrlen < 0)
934      return laddrlen;
935  }
936  *addrlen = laddrlen;
937  return rcvlen;
938}
939
940int
941Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen)
942{
943  struct sockaddr_storage laddr;
944  int laddrlen = sizeof(laddr);
945  int retcode = getpeername(sd, (struct sockaddr *) &laddr, &laddrlen);
946
947  if(!retcode) {
948    laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
949    if(laddrlen < 0)
950      return laddrlen;
951    *addrlen = laddrlen;
952  }
953
954  return retcode;
955}
956
957int
958Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen)
959{
960  struct sockaddr_storage laddr;
961  int laddrlen = sizeof(laddr);
962  int retcode = getsockname(sd, (struct sockaddr *) &laddr, &laddrlen);
963
964  if(!retcode) {
965    laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen);
966    if(laddrlen < 0)
967      return laddrlen;
968    *addrlen = laddrlen;
969  }
970
971  return retcode;
972}
973
974
975#ifdef HAVE_LIBZ
976const char *
977Curl_os400_zlibVersion(void)
978{
979  return set_thread_string(LK_ZLIB_VERSION, zlibVersion());
980}
981
982
983int
984Curl_os400_inflateInit_(z_streamp strm, const char *version, int stream_size)
985{
986  z_const char *msgb4 = strm->msg;
987  int ret;
988
989  ret = inflateInit(strm);
990
991  if(strm->msg != msgb4)
992    strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
993
994  return ret;
995}
996
997int
998Curl_os400_inflateInit2_(z_streamp strm, int windowBits,
999                         const char *version, int stream_size)
1000{
1001  z_const char *msgb4 = strm->msg;
1002  int ret;
1003
1004  ret = inflateInit2(strm, windowBits);
1005
1006  if(strm->msg != msgb4)
1007    strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1008
1009  return ret;
1010}
1011
1012int
1013Curl_os400_inflate(z_streamp strm, int flush)
1014{
1015  z_const char *msgb4 = strm->msg;
1016  int ret;
1017
1018  ret = inflate(strm, flush);
1019
1020  if(strm->msg != msgb4)
1021    strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1022
1023  return ret;
1024}
1025
1026int
1027Curl_os400_inflateEnd(z_streamp strm)
1028{
1029  z_const char *msgb4 = strm->msg;
1030  int ret;
1031
1032  ret = inflateEnd(strm);
1033
1034  if(strm->msg != msgb4)
1035    strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg);
1036
1037  return ret;
1038}
1039
1040#endif
1041