1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2015-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8%%	module
9
10
11#include "dk4conf.h"
12#include <libdk4sock/dk4sock.h>
13#include <libdk4socka/dk4socka.h>
14#include <libdk4base/dk4mem.h>
15
16#if DK4_HAVE_GETADDRINFO
17#include <libdk4maio8d/dk4mao8d.h>
18#else
19#if DK4_CHAR_SIZE > 1
20#include <libdk4maiowd/dk4maiwdus.h>
21#include <libdk4c/dk4rec24.h>
22#endif
23#include <libdk4maio8d/dk4mai8dus.h>
24#endif
25
26#include <libdk4maiodd/dk4maiddus.h>
27#include <libdk4maiodd/dk4maodd.h>
28#include <libdk4maiodh/dk4maodh.h>
29
30#if DK4_HAVE_ASSERT_H
31#ifndef	ASSERT_H_INCLUDED
32#include <assert.h>
33#define	ASSERT_H_INCLUDED 1
34#endif
35#endif
36
37
38$!trace-include
39
40
41
42/**	Constant texts used by module, not localized.
43*/
44static const dkChar * const	dk4socket_03_kwnl[] = {
45$!string-table	macro=dkT
46#
47#	0	Separator to switch to next line.
48#
49\n\t
50#
51#	1	Separator between function name and message text
52#
53:
54#
55#	2	Separator between service and host name
56#
57@
58$!end
59};
60
61
62
63/*
64	Internal tool functions
65	-----------------------
66*/
67
68/**	Report error from dk4socket_tcp_client_for_addr().
69	@param	app		Application structure for logging.
70	@param	afam		Address family.
71	@param	sremote		Pointer to remote address buffer.
72	@param	szremote	Remote address size.
73	@param	slocal		Pointer to local address buffer.
74	@param	szlocal		Local address size.
75	@param	erp		Error report, required.
76*/
77static
78void
79dk4socket_report_connection_error(
80  dk4_app_t		*app,
81  int			 afam,
82  const struct sockaddr	*sremote,
83  size_t		 szremote,
84  const struct sockaddr	*slocal,
85  size_t		 szlocal,
86  dk4_er_t		*erp
87)
88{
89  const	dkChar *	 msgt[32];		/* Message components */
90  dkChar		 bdec[16*sizeof(dk4_um_t)];	/* Decimal */
91  dkChar		 bhex[16*sizeof(dk4_um_t)];	/* Hexadecimal */
92  dkChar		 bloc[128];		/* Local address */
93  dkChar		 brem[128];		/* Remote address */
94  const dkChar * const	*msga		= NULL;	/* Localized texts */
95  const dkChar		*fctname	= NULL;	/* Name of failed function */
96  const	dkChar		*msgtext	= NULL;	/* Text why fct failed */
97#if VERSION_BEFORE_20150821
98  size_t		 szmsga		= 0;	/* Number of elems in msga */
99#endif
100  size_t		 used		= 0;	/* No used elems in msgt */
101  int			 res		= 0;	/* Conversion result */
102  int			 bothbuf	= 0;	/* Flag: Have bdec and bhex */
103  int			 fctnmsg	= 0;	/* Flag: Use fct name */
104  $? "+ dk4socket_report_connection_error"
105  if (NULL != app) {
106    if (dk4app_log_do(app, DK4_LL_ERROR)) {
107#if VERSION_BEFORE_20150821
108      szmsga = dk4socket_log_num_texts();
109#endif
110      msga   = dk4socket_log_texts(app);
111      dk4socket_log_fctname_msg(&fctname, &msgtext, app, erp);
112      if (NULL == msgtext) {
113        res = dk4ma_write_decimal_signed(
114	  bdec, DK4_SIZEOF(bdec,dkChar), (dk4_im_t)(erp->dt.iDetails1), 0, NULL
115	);
116	if (0 != res) {
117	  res = dk4ma_write_hex_signed(
118	    bhex,DK4_SIZEOF(bhex,dkChar),(dk4_im_t)(erp->dt.iDetails1),0,NULL
119	  );
120	  if (0 != res) { bothbuf = 1; }
121	}
122      }
123      msgt[used++] = msga[41];
124      if ((NULL != slocal) && (0 < szlocal)) {
125        res = dk4socket_addr_port_to_text(
126	  bloc, DK4_SIZEOF(bloc,dkChar), afam, slocal, szlocal, NULL
127	);
128	if (DK4_SOCKET_RESULT_SUCCESS == res) {
129	  msgt[used++] = dk4socket_03_kwnl[0];
130	  msgt[used++] = msga[42];
131	  msgt[used++] = bloc;
132	}
133      }
134      if ((NULL != sremote) && (0 < szremote)) {
135        res = dk4socket_addr_port_to_text(
136	  brem, DK4_SIZEOF(brem,dkChar), afam, sremote, szremote, NULL
137	);
138	if (DK4_SOCKET_RESULT_SUCCESS == res) {
139	  msgt[used++] = dk4socket_03_kwnl[0];
140	  msgt[used++] = msga[43];
141	  msgt[used++] = brem;
142	}
143      }
144      switch (erp->ec) {
145        case DK4_E_INVALID_ARGUMENTS : {
146	  msgt[used++] = dk4socket_03_kwnl[0];
147	  msgt[used++] = msga[45];
148	} break;
149	case DK4_E_SOCKET_SOCKET : {
150	  fctnmsg = 1;
151	  msgt[used++] = dk4socket_03_kwnl[0];
152	  msgt[used++] = msga[2];
153	} break;
154	case DK4_E_SOCKET_BIND : {
155	  fctnmsg = 1;
156	  msgt[used++] = dk4socket_03_kwnl[0];
157	  msgt[used++] = msga[4];
158	} break;
159	case DK4_E_SOCKET_FCNTL : {
160	  fctnmsg = 1;
161	  msgt[used++] = dk4socket_03_kwnl[0];
162	  msgt[used++] = msga[9];
163	} break;
164	case DK4_E_SOCKET_IOCTLSOCKET : {
165	  fctnmsg = 1;
166	  msgt[used++] = dk4socket_03_kwnl[0];
167	  msgt[used++] = msga[9];
168	} break;
169	case DK4_E_SOCKET_CONNECT : {
170	  fctnmsg = 1;
171	  msgt[used++] = dk4socket_03_kwnl[0];
172	  msgt[used++] = msga[7];
173	} break;
174	case DK4_E_SOCKET_TIMEOUT : {
175	  msgt[used++] = dk4socket_03_kwnl[0];
176	  msgt[used++] = msga[44];
177	} break;
178	case DK4_E_SOCKET_SELECT : {
179	  fctnmsg = 1;
180	  msgt[used++] = dk4socket_03_kwnl[0];
181	  msgt[used++] = msga[44];
182	} break;
183	case DK4_E_SOCKET_GETSOCKOPT : {
184	  fctnmsg = 1;
185	  msgt[used++] = dk4socket_03_kwnl[0];
186	  msgt[used++] = msga[8];
187	} break;
188	case DK4_E_SOCKET_SETSOCKOPT : {
189	  fctnmsg = 1;
190	  msgt[used++] = dk4socket_03_kwnl[0];
191	  msgt[used++] = msga[8];
192	} break;
193      }
194      if (0 != fctnmsg) {
195        if ((NULL != fctname) && ((NULL != msgtext) || (0 != bothbuf))) {
196	  msgt[used++] = dk4socket_03_kwnl[0];
197	  msgt[used++] = fctname;
198	  msgt[used++] = dk4socket_03_kwnl[1];
199	  if (NULL != msgtext) {
200	    msgt[used++] = msgtext;
201	  } else {
202#if DK4_ON_WINDOWS
203	    msgt[used++] = msga[40];
204#else
205	    msgt[used++] = msga[37];
206#endif
207	    msgt[used++] = bdec;
208	    msgt[used++] = msga[38];
209	    msgt[used++] = bhex;
210	    msgt[used++] = msga[39];
211	  }
212	}
213      }
214      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
215    }
216  }
217  $? "- dk4socket_report_connection_error"
218}
219
220
221
222/**	Report error from dk4socket_tcp_client_for_addr().
223	@param	app		Application structure for logging.
224	@param	afam		Address family.
225	@param	sremote		Pointer to remote address buffer.
226	@param	szremote	Remote address size.
227	@param	slocal		Pointer to local address buffer.
228	@param	szlocal		Local address size.
229	@param	erp		Error report, required.
230*/
231static
232void
233dk4socket_report_connection_established(
234  dk4_app_t		*app,
235  int			 afam,
236  const struct sockaddr	*sremote,
237  size_t		 szremote,
238  const struct sockaddr	*slocal,
239  size_t		 szlocal
240)
241{
242  const	dkChar *	 msgt[32];		/* Message components */
243  dkChar		 bloc[128];		/* Local address */
244  dkChar		 brem[128];		/* Remote address */
245  const dkChar * const	*msga		= NULL;	/* Localized texts */
246#if VERSION_BEFORE_20150821
247  size_t		 szmsga		= 0;	/* Number of elems in msga */
248#endif
249  size_t		 used		= 0;	/* No used elems in msgt */
250  int			 res		= 0;	/* Conversion result */
251
252  if (NULL != app) {
253    if (0 != dk4app_log_do(app, DK4_LL_PROGRESS)) {
254#if VERSION_BEFORE_20150821
255      szmsga = dk4socket_log_num_texts();
256#endif
257      msga   = dk4socket_log_texts(app);
258      msgt[used++] = msga[30];
259      if ((NULL != slocal) && (0 < szlocal)) {
260        res = dk4socket_addr_port_to_text(
261	  bloc, DK4_SIZEOF(bloc,dkChar), afam, slocal, szlocal, NULL
262	);
263	if (DK4_SOCKET_RESULT_SUCCESS == res) {
264	  msgt[used++] = dk4socket_03_kwnl[0];
265	  msgt[used++] = msga[42];
266	  msgt[used++] = bloc;
267	}
268      }
269      if ((NULL != sremote) && (0 < szremote)) {
270        res = dk4socket_addr_port_to_text(
271	  brem, DK4_SIZEOF(brem,dkChar), afam, sremote, szremote, NULL
272	);
273	if (DK4_SOCKET_RESULT_SUCCESS == res) {
274	  msgt[used++] = dk4socket_03_kwnl[0];
275	  msgt[used++] = msga[43];
276	  msgt[used++] = brem;
277	}
278      }
279      dk4app_log_msg(app, DK4_LL_PROGRESS, msgt, used);
280    }
281  }
282}
283
284
285
286static
287void
288dk4socket_report_invalid_arguments(
289  dk4_app_t	*app
290)
291{
292  const dkChar *	 msgt[16];
293  const dkChar * const	*msga;
294#if VERSION_BEFORE_20150821
295  size_t		 szmsga;
296#endif
297  size_t		 used = 0;
298  if (NULL != app) {
299    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
300#if VERSION_BEFORE_20150821
301      szmsga = dk4socket_log_num_texts();
302#endif
303      msga   = dk4socket_log_texts(app);
304      msgt[used++] = msga[41];
305      msgt[used++] = dk4socket_03_kwnl[0];
306      msgt[used++] = msga[45];
307      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
308    }
309  }
310}
311
312
313#if DK4_HAVE_GETADDRINFO
314/* +++++ +getaddrinfo +++++ */
315
316static
317void
318dk4socket_report_no_matching_addresses(
319  const dkChar	*hostname,
320  dk4_app_t	*app
321)
322{
323  const dkChar		*msgt[16];
324  const dkChar * const	*msga;
325#if VERSION_BEFORE_20150821
326  size_t		 szmsga;
327#endif
328  if (NULL != app) {
329    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
330#if VERSION_BEFORE_20150821
331      szmsga = dk4socket_log_num_texts();
332#endif
333      msga   = dk4socket_log_texts(app);
334      msgt[0] = msga[41];
335      msgt[1] = dk4socket_03_kwnl[0];
336      msgt[2] = msga[43];
337      msgt[4] = hostname;
338      msgt[5] = dk4socket_03_kwnl[0];
339      msgt[6] = msga[46];
340      dk4app_log_msg(app, DK4_LL_ERROR, msgt, 7);
341    }
342  }
343}
344
345
346
347static
348void
349dk4socket_report_gai(
350  const dkChar	*hostname,
351  const dkChar	*lsvcname,
352  int		 res,
353  int		 local,
354  dk4_app_t	*app,
355  dk4_er_t	*erp
356)
357{
358  dkChar		 bdec[16*sizeof(dk4_um_t)];
359  dkChar		 bhex[16*sizeof(dk4_um_t)];
360  const dkChar 		*msgt[16];
361  const dkChar * const	*msga;
362  const dkChar		*fctname	= NULL;
363  const dkChar		*msgtext	= NULL;
364#if VERSION_BEFORE_20150821
365  size_t		 szmsga;
366#endif
367  size_t		 used = 0;
368
369  if (NULL != app) {
370    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
371#if VERSION_BEFORE_20150821
372      szmsga = dk4socket_log_num_texts();
373#endif
374      msga   = dk4socket_log_texts(app);
375      dk4socket_log_fctname_msg(&fctname, &msgtext, app, erp);
376      msgt[used++] = msga[41];
377      if ((NULL != hostname) && (0 == local)) {
378        msgt[used++] = dk4socket_03_kwnl[0];
379	msgt[used++] = msga[20];
380	msgt[used++] = dk4socket_03_kwnl[0];
381	msgt[used++] = msga[21];
382	msgt[used++] = hostname;
383	if (NULL != lsvcname) {
384	  msgt[used++] = dk4socket_03_kwnl[0];
385	  msgt[used++] = msga[22];
386	  msgt[used++] = lsvcname;
387	}
388      } else {
389        msgt[used++] = dk4socket_03_kwnl[0];
390        msgt[used++] = msga[18];
391	msgt[used++] = dk4socket_03_kwnl[0];
392	msgt[used++] = msga[19];
393	msgt[used++] = lsvcname;
394      }
395      if (NULL != fctname) {
396        if (NULL != msgtext) {
397	  msgt[used++] = dk4socket_03_kwnl[0];
398	  msgt[used++] = fctname;
399	  msgt[used++] = dk4socket_03_kwnl[1];
400	  msgt[used++] = msgtext;
401	} else {
402	  res = dk4ma_write_decimal_signed(
403	    bdec,DK4_SIZEOF(bdec,dkChar),(dk4_im_t)(erp->dt.iDetails1),0,NULL
404	  );
405	  if (0 != res) {
406	    res = dk4ma_write_hex_signed(
407	      bhex,DK4_SIZEOF(bhex,dkChar),(dk4_im_t)(erp->dt.iDetails1),0,NULL
408	    );
409	    if (0 != res) {
410	      msgt[used++] = dk4socket_03_kwnl[0];
411	      msgt[used++] = fctname;
412	      msgt[used++] = dk4socket_03_kwnl[1];
413#if DK4_ON_WINDOWS
414	      msgt[used++] = msga[40];
415#else
416	      msgt[used++] = msga[37];
417#endif
418	      msgt[used++] = bdec;
419	      msgt[used++] = msga[38];
420	      msgt[used++] = bhex;
421	      msgt[used++] = msga[39];
422	    }
423	  }
424	}
425      } else {
426      }
427      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
428    }
429  }
430}
431
432#if DK4_CHAR_SIZE > 1
433
434/**	Create a socket using remote and optionally local address lists.
435	@param	hostname	Remote host name.
436	@param	rast	List of remote addresses.
437	@param	last	List of local addresses, may be NULL.
438	@param	secs	Seconds for timeout.
439	@param	usecs	Microseconds for timeout.
440	@param	app	Application structure for diagnostics, may be NULL.
441	@return	Valid socket on success, INVALID_SOCKET on error.
442*/
443static
444dk4_socket_t
445dk4socket_tcp_client_addresses_app(
446  const dkChar		*hostname,
447  ADDRINFOW		*rast,
448  ADDRINFOW		*last,
449  long			 secs,
450  long			 usecs,
451  dk4_app_t		*app
452)
453{
454  dk4_er_t		 er;
455  ADDRINFOW		*ra;
456  ADDRINFOW		*la;
457  dk4_socket_t		 back	= INVALID_SOCKET;
458  int			 mpf	= 0;
459  $? "+ dk4socket_tcp_client_addresses_app %d %d", TR_IPTR(rast), TR_IPTR(last)
460  ra = rast;
461  while ((INVALID_SOCKET == back) && (NULL != ra)) {
462    if (NULL != last) {
463      la = last;
464      while ((INVALID_SOCKET == back) && (NULL != la)) {
465        if (ra->ai_family == la->ai_family) {
466	  mpf = 1;		$? ". families match, attempt to connect"
467	  dk4error_init(&er);
468	  back = dk4socket_tcp_client_for_addr(
469	    ra->ai_family,
470	    ra->ai_addr, ra->ai_addrlen,
471	    la->ai_addr, la->ai_addrlen,
472	    secs, usecs, &er
473	  );
474	  if (INVALID_SOCKET != back) {
475	    dk4socket_report_connection_established(
476	      app, ra->ai_family,
477	      ra->ai_addr, ra->ai_addrlen,
478	      la->ai_addr, la->ai_addrlen
479	    );
480	    ra = NULL; la = NULL;
481	  } else {		$? "! report failure"
482	    /* ERROR: Failed */
483	    dk4socket_report_connection_error(
484	      app, ra->ai_family,
485	      ra->ai_addr, ra->ai_addrlen,
486	      la->ai_addr, la->ai_addrlen,
487	      &er
488	    );
489	  }
490	}
491        if (NULL != la) { la = la->ai_next; }
492      }
493    } else {
494      mpf = 1;
495      dk4error_init(&er);
496      back = dk4socket_tcp_client_for_addr(
497        ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0, secs, usecs, &er
498      );
499      if (INVALID_SOCKET != back) {
500	dk4socket_report_connection_established(
501	  app, ra->ai_family,
502	  ra->ai_addr, ra->ai_addrlen,
503	  NULL, 0
504	);
505        ra = NULL;
506      } else {			$? "! report failure"
507        /* ERROR: Failed */
508	dk4socket_report_connection_error(
509	  app,ra->ai_family,ra->ai_addr,ra->ai_addrlen,NULL,0,&er
510	);
511      }
512    }
513    if (NULL != ra) { ra = ra->ai_next; }
514  }
515  if (INVALID_SOCKET == back) {
516    if (0 == mpf) {		$? ". report no matching families"
517      /* ERROR: No matching address pair found (27) */
518      dk4socket_report_no_matching_addresses(hostname, app);
519    }
520  }
521  $? "- dk4socket_tcp_client_addresses_app %d", (int)back
522  return back;
523}
524
525#else
526
527/**	Create a socket using remote and optionally local address lists.
528	@param	hostname	Remote host name.
529	@param	rast	List of remote addresses.
530	@param	last	List of local addresses, may be NULL.
531	@param	secs	Seconds for timeout.
532	@param	usecs	Microseconds for timeout.
533	@param	app	Application structure for diagnostics, may be NULL.
534	@return	Valid socket on success, INVALID_SOCKET on error.
535*/
536static
537dk4_socket_t
538dk4socket_tcp_client_addresses_app(
539  const dkChar		*hostname,
540  struct addrinfo	*rast,
541  struct addrinfo	*last,
542  long			 secs,
543  long			 usecs,
544  dk4_app_t		*app
545)
546{
547  dk4_er_t		 er;
548  struct addrinfo	*ra;
549  struct addrinfo	*la;
550  dk4_socket_t		 back	= INVALID_SOCKET;
551  int			 mpf	= 0;
552  $? "+ dk4socket_tcp_client_addresses_app %d %d", TR_IPTR(rast), TR_IPTR(last)
553  ra = rast;
554  while ((INVALID_SOCKET == back) && (NULL != ra)) {
555    if (NULL != last) {
556      la = last;
557      while ((INVALID_SOCKET == back) && (NULL != la)) {
558        if (ra->ai_family == la->ai_family) {
559	  mpf = 1;
560	  dk4error_init(&er);
561	  back = dk4socket_tcp_client_for_addr(
562	    ra->ai_family,
563	    ra->ai_addr, ra->ai_addrlen,
564	    la->ai_addr, la->ai_addrlen,
565	    secs, usecs, &er
566	  );
567	  if (INVALID_SOCKET != back) {
568	    dk4socket_report_connection_established(
569	      app, ra->ai_family,
570	      ra->ai_addr, ra->ai_addrlen,
571	      la->ai_addr, la->ai_addrlen
572	    );
573	    ra = NULL; la = NULL;
574	  } else {			$? "! report failure"
575	    /* ERROR: Failed */
576	    dk4socket_report_connection_error(
577	      app, ra->ai_family,
578	      ra->ai_addr, ra->ai_addrlen,
579	      la->ai_addr, la->ai_addrlen,
580	      &er
581	    );
582	  }
583	}
584        if (NULL != la) { la = la->ai_next; }
585      }
586    } else {
587      mpf = 1;
588      dk4error_init(&er);
589      back = dk4socket_tcp_client_for_addr(
590        ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0, secs, usecs, &er
591      );
592      if (INVALID_SOCKET != back) {
593	dk4socket_report_connection_established(
594	  app, ra->ai_family,
595	  ra->ai_addr, ra->ai_addrlen,
596	  NULL, 0
597	);
598        ra = NULL;
599      } else {				$? "! report failure"
600        /* ERROR: Failed */
601	dk4socket_report_connection_error(
602	  app,ra->ai_family,ra->ai_addr,ra->ai_addrlen,NULL,0,&er
603	);
604      }
605    }
606    if (NULL != ra) { ra = ra->ai_next; }
607  }
608  if (INVALID_SOCKET == back) {
609    if (0 == mpf) {
610      /* ERROR: No matching address pair found (27) */
611      dk4socket_report_no_matching_addresses(hostname, app);
612    }
613  }
614  $? "- dk4socket_tcp_client_addresses_app %d", (int)back
615  return back;
616}
617
618#endif
619
620/* ----- +getaddrinfo ----- */
621#else
622/* +++++ -getaddrinfo +++++ */
623
624#if DK4_HAVE_STRUCT_SOCKADDR_IN6
625/**	used to initialize IPv6 address for binding local ports.
626*/
627static const IN6_ADDR dk4socket_any6 = IN6ADDR_ANY_INIT;
628#endif
629
630static
631void
632dk4socket_report_invalid_port_number(dk4_app_t *app, size_t i)
633{
634  const dkChar *	 msgt[16];
635  const dkChar * const	*msga;
636  size_t		 szmsga;
637  size_t		 used = 0;
638
639  if (NULL != app) {
640    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
641      szmsga = dk4socket_log_num_texts();
642      msga   = dk4socket_log_texts(app);
643      msgt[used++] = msga[41];
644      msgt[used++] = dk4socket_03_kwnl[0];
645      msgt[used++] = msga[i];
646      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
647    }
648  }
649}
650
651
652static
653void
654dk4socket_report_service_not_found(dk4_app_t *app, const dkChar *svcname)
655{
656  const dkChar *	 msgt[16];
657  const dkChar * const	*msga;
658  size_t		 szmsga;
659  size_t		 used = 0;
660
661  if (NULL != app) {
662    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
663      szmsga = dk4socket_log_num_texts();
664      msga   = dk4socket_log_texts(app);
665      msgt[used++] = msga[23];
666      msgt[used++] = svcname;
667      msgt[used++] = msga[24];
668      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
669    }
670  }
671}
672
673
674
675#if DK4_CHAR_SIZE > 1
676
677static
678void
679dk4socket_report_service_not_ascii(dk4_app_t *app, const dkChar *svcname)
680{
681  const dkChar *	 msgt[16];
682  const dkChar * const	*msga;
683  size_t		 szmsga;
684  size_t		 used = 0;
685
686  if (NULL != app) {
687    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
688      szmsga = dk4socket_log_num_texts();
689      msga   = dk4socket_log_texts(app);
690      msgt[used++] = msga[25];
691      msgt[used++] = svcname;
692      msgt[used++] = msga[26];
693      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
694    }
695  }
696}
697
698#endif
699
700
701
702static
703void
704dk4socket_report_illegal_address_part(
705  dk4_app_t	*app,
706  const dkChar	*hostname,
707  size_t	 i
708)
709{
710  const dkChar *	 msgt[16];
711  const dkChar * const	*msga;
712  size_t		 szmsga;
713  size_t		 used = 0;
714
715  if (NULL != app) {
716    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
717      szmsga = dk4socket_log_num_texts();
718      msga   = dk4socket_log_texts(app);
719      msgt[used++] = msga[i];
720      if (NULL != hostname) {
721        msgt[used++] = dk4socket_03_kwnl[0];
722	msgt[used++] = msga[43];
723	msgt[used++] = hostname;
724      }
725      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
726    }
727  }
728}
729
730
731
732static
733void
734dk4socket_report_host_name_problem(
735  dk4_app_t	*app,
736  const dkChar	*hostname,
737  size_t	 i1,
738  size_t	 i2
739)
740{
741  const dkChar *	 msgt[16];
742  const dkChar * const	*msga;
743  size_t		 szmsga;
744  size_t		 used = 0;
745
746  if (NULL != app) {
747    if (0 != dk4app_log_do(app, DK4_LL_ERROR)) {
748      szmsga = dk4socket_log_num_texts();
749      msga   = dk4socket_log_texts(app);
750      if (NULL != hostname) {
751	msgt[used++] = msga[i1];
752	msgt[used++] = hostname;
753	msgt[used++] = msga[i2];
754      }
755      dk4app_log_msg(app, DK4_LL_ERROR, msgt, used);
756    }
757  }
758}
759
760/* ----- -getaddrinfo ----- */
761#endif
762
763
764
765/*
766	Exported functions
767	------------------
768*/
769
770#if DK4_CHAR_SIZE > 1
771#if DK4_ON_WINDOWS
772#if DK4_HAVE_GETADDRINFO
773/* +++++ wchar_t (Windows), +getaddrinfo +++++ */
774
775
776
777dk4_socket_t
778dk4socket_tcp_client_for_host_num_service_app(
779  const	dkChar		*hostname,
780  const	dkChar		*svcname,
781  const dkChar		*lsvcname,
782  long			 secs,
783  long			 usecs,
784  int			 nsrv,
785  dk4_app_t		*app
786)
787{
788  ADDRINFOW		 rhints;
789  ADDRINFOW		 lhints;
790  dk4_er_t		 er;
791  ADDRINFOW		*rast	= NULL;
792  ADDRINFOW		*last	= NULL;
793  dk4_socket_t		 back	= INVALID_SOCKET;
794  int			 res;
795  $? "+ dk4socket_tcp_client_for_host_num_service_app (wchar_t +getaddrinfo)"
796#if	DK4_USE_ASSERT
797  assert(NULL != hostname);
798  assert(NULL != svcname);
799#endif
800  if ((NULL != hostname) && (NULL != svcname)) {		$? ". args ok"
801    DK4_MEMRES(&rhints, sizeof(rhints));
802    rhints.ai_family = AF_UNSPEC;
803    rhints.ai_socktype = SOCK_STREAM;
804    if (0 != nsrv) { rhints.ai_flags = AI_NUMERICSERV; }
805    rhints.ai_protocol = 0;
806    dk4error_init(&er);
807    res = GetAddrInfoW(hostname, svcname, &rhints, &rast);
808    if ((0 == res) && (NULL != rast)) {	$? ". getaddrinfo (remote)"
809      if (NULL != lsvcname) {			$? ". local service name"
810        DK4_MEMRES(&lhints, sizeof(lhints));
811	lhints.ai_family = AF_UNSPEC;
812	lhints.ai_socktype = SOCK_STREAM;
813	lhints.ai_flags = AI_PASSIVE;
814	if (0 != nsrv) { lhints.ai_flags |= AI_NUMERICSERV; }
815	lhints.ai_protocol = 0;
816	dk4error_init(&er);
817	res = GetAddrInfoW(NULL, lsvcname, &lhints, &last);
818	if ((0 == res) && (NULL != last)) {	$? ". getaddrinfo local"
819	  back = dk4socket_tcp_client_addresses_app(
820	    hostname, rast, last, secs, usecs, app
821	  );
822	  FreeAddrInfoW(last);
823	} else {				$? "! getaddrinfo local"
824	  /* ERROR: Failed to obtain local addresses to bind (18, 19) */
825	  dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res);
826	  dk4socket_report_gai(NULL, lsvcname, res, 1, app, &er);
827	}
828      } else {					$? ". no local service name"
829        back = dk4socket_tcp_client_addresses_app(
830	  hostname, rast, NULL, secs, usecs, app
831	);
832      }
833      FreeAddrInfoW(rast);
834    } else {					$? "! getaddrinfo (remote)"
835      /* ERROR: Failed to obtain remote addresses (20, 21, 22) */
836      dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res);
837      dk4socket_report_gai(hostname, svcname, res, 0, app, &er);
838    }
839  } else {						$? "! args"
840    /* ERROR: Invalid arguments (bug) */
841    dk4socket_report_invalid_arguments(app);
842  }
843  $? "- dk4socket_tcp_client_for_host_num_service_app (wchar_t) %d", (int)back
844  return back;
845}
846
847
848
849dk4_socket_t
850dk4socket_tcp_client_for_host_service_app(
851  const	dkChar		*hostname,
852  const	dkChar		*svcname,
853  const dkChar		*lsvcname,
854  long			 secs,
855  long			 usecs,
856  dk4_app_t		*app
857)
858{
859  return (
860    dk4socket_tcp_client_for_host_num_service_app(
861      hostname, svcname, lsvcname, secs, usecs, 0, app
862    )
863  );
864}
865
866
867
868dk4_socket_t
869dk4socket_tcp_client_for_host_port_app(
870  const dkChar		*hostname,
871  unsigned short	 portno,
872  unsigned short	 lportno,
873  long			 secs,
874  long			 usecs,
875  dk4_app_t		*app
876)
877{
878  dkChar		 rpnb[16*sizeof(dk4_um_t)];
879  dkChar		 lpnb[16*sizeof(dk4_um_t)];
880  dk4_er_t		 er;
881  dk4_socket_t		 back	= INVALID_SOCKET;
882  int			 res;
883  $? "+ dk4socket_tcp_client_for_host_port_app (wchar_t)"
884#if	DK4_USE_ASSERT
885  assert(NULL != hostname);
886  assert(0 < portno);
887#endif
888  if ((NULL != hostname) && (0 < portno)) {			$? ". args ok"
889    dk4error_init(&er);
890    res = dk4ma_write_decimal_unsigned(
891      rpnb, DK4_SIZEOF(rpnb,dkChar), (dk4_um_t)portno, 0, &er
892    );
893    if (0 != res) {					$? ". num to text"
894      if (0 < lportno) {				$? ". local port"
895        dk4error_init(&er);
896        res = dk4ma_write_decimal_unsigned(
897	  lpnb, DK4_SIZEOF(lpnb,dkChar), (dk4_um_t)lportno, 0, &er
898	);
899	if (0 != res) {					$? ". num to text"
900	  back = dk4socket_tcp_client_for_host_num_service_app(
901	    hostname, rpnb, lpnb, secs, usecs, 0, app
902	  );
903	} else {					$? "! bug"
904	  /* ERROR: Failed to convert local port number to text, bug */
905	}
906      } else {						$? ". no local port"
907	back = dk4socket_tcp_client_for_host_num_service_app(
908	  hostname, rpnb, NULL, secs, usecs, 0, app
909	);
910      }
911    } else {						$? "! num to text"
912      /* ERROR: Failed to convert port number to text, bug */
913    }
914  } else {						$? "! args"
915    /* ERROR: Invalid arguments (bug) */
916    dk4socket_report_invalid_arguments(app);
917  }
918  $? "- dk4socket_tcp_client_for_host_port_app (wchar_t) %d", (int)back
919  return back;
920}
921
922
923
924/* ----- wchar_t (Windows), +getaddrinfo ----- */
925#else
926/* +++++ wchar_t (Windows), -getaddrinfo +++++ */
927
928
929
930dk4_socket_t
931dk4socket_tcp_client_for_host_num_service_app(
932  const	dkChar		*hostname,
933  const	dkChar		*svcname,
934  const dkChar		*lsvcname,
935  long			 secs,
936  long			 usecs,
937  int			 nsrv,
938  dk4_app_t		*app
939)
940{
941  char			 cppt[48];
942  char			 cplp[48];
943  dk4_er_t		 er;
944  struct servent	*serv	= NULL;
945  const dkChar		*endptr	= NULL;
946  dk4_socket_t		 back	= INVALID_SOCKET;
947  int			 res	= 0;
948  unsigned short	 rport	= 0U;
949  unsigned short	 lport	= 0U;
950  unsigned short	 iport	= 0U;
951  $? "+ dk4socket_tcp_client_for_host_num_service_app (wchar_t)"
952#if	DK4_USE_ASSERT
953  assert(NULL != hostname);
954  assert(NULL != svcname);
955#endif
956  if ((NULL != hostname) && (NULL != svcname)) {
957    dk4error_init(&er);
958    res = dk4ma_input_dk_dec_ushort(&rport, svcname, &endptr, 1, NULL);
959    if (0 == res) {
960      if (0 != dk4recode_wchar_t_to_char(cppt, sizeof(cppt), svcname, &er)) {
961        dk4socket_error_reset();
962	serv = getservbyname(cppt, NULL);
963	if (NULL != serv) {
964	  iport = serv->s_port;
965	  dk4socket_swap_bytes_if_not_bigendian((void *)(&iport),sizeof(iport));
966	  rport = (unsigned short)iport;
967	} else {
968	  dk4socket_error_report(&er, DK4_E_SOCKET_GETSERVBYNAME);
969	  /* ERROR: Service not found (23, 24) */
970	  dk4socket_report_service_not_found(app, svcname);
971	}
972      } else {
973        /* ERROR: Failed to convert service name (25, 26) */
974	dk4socket_report_service_not_ascii(app, svcname);
975      }
976    }
977    if (0 < rport) {
978      if (NULL != lsvcname) {
979        endptr = NULL;
980	dk4error_init(&er);
981	res = dk4ma_input_dk_dec_ushort(&lport, lsvcname, &endptr, 1, NULL);
982	if (0 == res) {
983	  dk4error_init(&er);
984	  if (0 != dk4recode_wchar_t_to_char(cplp,sizeof(cplp),lsvcname,&er)) {
985	    dk4socket_error_reset();
986	    serv = getservbyname(cplp, NULL);
987	    if (NULL != serv) {
988	      iport = serv->s_port;
989	      dk4socket_swap_bytes_if_not_bigendian(
990	        (void *)(&iport), sizeof(iport)
991	      );
992	      lport = (unsigned short)iport;
993	    } else {
994	      dk4socket_error_report(&er, DK4_E_SOCKET_GETSERVBYNAME);
995	      /* Service not found (23, 24) */
996	      dk4socket_report_service_not_found(app, lsvcname);
997	    }
998	  } else {
999	    /* ERROR: Text conversion failed (25, 26) */
1000	    dk4socket_report_service_not_ascii(app, lsvcname);
1001	  }
1002	}
1003	if (0 < lport) {
1004	  back = dk4socket_tcp_client_for_host_port_app(
1005	    hostname, rport, lport, secs, usecs, app
1006	  );
1007	} else {
1008	  /* ERROR: Illegal local port number (28) */
1009	  dk4socket_report_invalid_port_number(app, 28);
1010	}
1011      } else {
1012        back = dk4socket_tcp_client_for_host_port_app(
1013	  hostname, rport, 0, secs, usecs, app
1014	);
1015      }
1016    } else {
1017      /* ERROR: Illegal remote port number (29) */
1018      dk4socket_report_invalid_port_number(app, 29);
1019    }
1020  } else {
1021    /* ERROR: Invalid arguments (bug) */
1022    dk4socket_report_invalid_arguments(app);
1023  }
1024  $? "- dk4socket_tcp_client_for_host_num_service_app (wchar_t) %d", (int)back
1025  return back;
1026}
1027
1028
1029
1030dk4_socket_t
1031dk4socket_tcp_client_for_host_service_app(
1032  const	dkChar		*hostname,
1033  const	dkChar		*svcname,
1034  const dkChar		*lsvcname,
1035  long			 secs,
1036  long			 usecs,
1037  dk4_app_t		*app
1038)
1039{
1040  return (
1041    dk4socket_tcp_client_for_host_num_service_app(
1042      hostname, svcname, lsvcname, secs, usecs, 0, app
1043    )
1044  );
1045}
1046
1047
1048
1049dk4_socket_t
1050dk4socket_tcp_client_for_host_port_app(
1051  const dkChar		*hostname,
1052  unsigned short	 portno,
1053  unsigned short	 lportno,
1054  long			 secs,
1055  long			 usecs,
1056  dk4_app_t		*app
1057)
1058{
1059  char			  hona[1040];
1060#if DK4_HAVE_STRUCT_SOCKADDR_IN6
1061  struct sockaddr_in6	  sr6;
1062  struct sockaddr_in6	  sl6;
1063#endif
1064  struct sockaddr_in	  sr4;
1065  struct sockaddr_in	  sl4;
1066  dk4_er_t		  er;
1067  char			**addrptr;
1068  struct hostent	 *hep;
1069  dk4_socket_t		  back	= INVALID_SOCKET;
1070
1071  $? "+ dk4socket_tcp_client_for_host_port_app (wchar_t)"
1072#if	DK4_USE_ASSERT
1073  assert(NULL != hostname);
1074  assert(0 < portno);
1075#endif
1076  if ((NULL != hostname) && (0 < portno)) {
1077    dk4error_init(&er);
1078    if (0 != dk4recode_wchar_t_to_char(hona, sizeof(hona), hostname, &er)) {
1079      dk4socket_error_reset();
1080      hep = gethostbyname(hona);
1081      if (NULL != hep) {
1082        if (NULL != hep->h_addr_list) {
1083	  switch (hep->h_addrtype) {
1084	    case AF_INET : {
1085	      if (4 == hep->h_length) {
1086	        addrptr = hep->h_addr_list;
1087		while ((INVALID_SOCKET == back) && (NULL != *addrptr)) {
1088		  DK4_MEMRES(&sr4, sizeof(sr4));
1089		  sr4.sin_family = AF_INET;
1090		  sr4.sin_port   = dk4socket_htons(portno);
1091		  DK4_MEMCPY(&(sr4.sin_addr), *addrptr, sizeof(IN_ADDR));
1092		  dk4error_init(&er);
1093		  if (0 != lportno) {
1094		    DK4_MEMRES(&sl4, sizeof(sl4));
1095		    sl4.sin_family = AF_INET;
1096		    sl4.sin_port   = dk4socket_htons(lportno);
1097		    sl4.sin_addr.s_addr = dk4socket_htonl(INADDR_ANY);
1098		    back = dk4socket_tcp_client_for_addr(
1099		      AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4),
1100		      (struct sockaddr *)(&sl4), sizeof(sl4), secs, usecs, &er
1101		    );
1102		  } else {
1103		    back = dk4socket_tcp_client_for_addr(
1104		      AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4),
1105		      NULL, 0, secs, usecs, &er
1106		    );
1107		  }
1108		  if (INVALID_SOCKET == back) {	$? "! report failure"
1109		    /* ERROR: Failed */
1110		    dk4socket_report_connection_error(
1111		      app, AF_INET,
1112		      (struct sockaddr *)(&sr4), sizeof(sr4),
1113		      ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL),
1114		      ((0 < lportno) ? (sizeof(sl4)) : 0),
1115		      &er
1116		    );
1117		  } else {
1118		    /* DEBUG: Connection established (30) */
1119		    dk4socket_report_connection_established(
1120		      app, AF_INET,
1121		      (struct sockaddr *)(&sr4), sizeof(sr4),
1122		      ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL),
1123		      ((0 < lportno) ? (sizeof(sl4)) : 0)
1124		    );
1125		  }
1126		  addrptr++;
1127		}
1128	      } else {
1129	        /* ERROR: Illegal address length, bug (31) */
1130		dk4socket_report_illegal_address_part(app, hostname, 31);
1131	      }
1132	    } break;
1133#if DK4_HAVE_STRUCT_SOCKADDR_IN6
1134	    case AF_INET6 : {
1135	      if (16 == hep->h_length) {
1136	        addrptr = hep->h_addr_list;
1137		while ((INVALID_SOCKET == back) && (NULL != *addrptr)) {
1138		  DK4_MEMRES(&sr6, sizeof(sr6));
1139		  sr6.sin6_family = AF_INET6;
1140		  sr6.sin6_port   = dk4socket_htons(portno);
1141		  DK4_MEMCPY(&(sr6.sin6_addr), *addrptr, sizeof(IN6_ADDR));
1142		  dk4error_init(&er);
1143		  if (0 < lportno) {
1144		    DK4_MEMRES(&sl6, sizeof(sl6));
1145		    sl6.sin6_family = AF_INET6;
1146		    sl6.sin6_port   = dk4socket_htons(lportno);
1147		    DK4_MEMCPY(&(sl6.sin6_addr),&dk4socket_any6,sizeof(IN6_ADDR));
1148		    back = dk4socket_tcp_client_for_addr(
1149		      AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6),
1150		      (struct sockaddr *)(&sl6), sizeof(sl6), secs, usecs, &er
1151		    );
1152		  } else {
1153		    back = dk4socket_tcp_client_for_addr(
1154		      AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6),
1155		      NULL, 0, secs, usecs, &er
1156		    );
1157		  }
1158		  if (INVALID_SOCKET == back) {		$? "! report failure"
1159		    /* ERROR: Failed */
1160		    dk4socket_report_connection_error(
1161		      app, AF_INET6,
1162		      (struct sockaddr *)(&sr6), sizeof(sr6),
1163		      ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL),
1164		      ((0 < lportno) ? (sizeof(sl6)) : 0),
1165		      &er
1166		    );
1167		  } else {
1168		    /* DEBUG: Connection established (30) */
1169		    dk4socket_report_connection_established(
1170		      app, AF_INET6,
1171		      (struct sockaddr *)(&sr6), sizeof(sr6),
1172		      ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL),
1173		      ((0 < lportno) ? (sizeof(sl6)) : 0)
1174		    );
1175		  }
1176		  addrptr++;
1177		}
1178	      } else {
1179	        /* ERROR: Illegal address length, bug (31) */
1180		dk4socket_report_illegal_address_part(app, hostname, 31);
1181	      }
1182	    } break;
1183#endif
1184	    default : {
1185	      /* ERROR: Illegal address family (32) */
1186	      dk4socket_report_illegal_address_part(app, hostname, 32);
1187	    } break;
1188	  }
1189	} else {
1190	  /* ERROR: Host not found (33, 34) */
1191	  dk4socket_report_host_name_problem(app, hostname, 33, 34);
1192	}
1193      } else {
1194        dk4socket_error_report(&er, DK4_E_SOCKET_GETHOSTBYNAME);
1195        /* ERROR: Host not found (33, 34) */
1196	dk4socket_report_host_name_problem(app, hostname, 33, 34);
1197      }
1198    } else {
1199      /* ERROR: Failed to convert host name to ASCII (35, 36) */
1200      dk4socket_report_host_name_problem(app, hostname, 35, 36);
1201    }
1202  } else {
1203    /* ERROR: Invalid arguments (bug) */
1204    dk4socket_report_invalid_arguments(app);
1205  }
1206  $? "- dk4socket_tcp_client_for_host_port_app (wchar_t) %d", (int)back
1207  return back;
1208}
1209
1210
1211
1212/* ----- wchar_t (Windows), -getaddrinfo ----- */
1213#endif
1214#else
1215#error	No support for networking with wchar_t strings!
1216#endif
1217#else
1218#if DK4_HAVE_GETADDRINFO
1219/* +++++ char, +getaddrinfo +++++ */
1220
1221dk4_socket_t
1222dk4socket_tcp_client_for_host_num_service_app(
1223  const	dkChar		*hostname,
1224  const	dkChar		*svcname,
1225  const dkChar		*lsvcname,
1226  long			 secs,
1227  long			 usecs,
1228  int			 nsrv,
1229  dk4_app_t		*app
1230)
1231{
1232  struct addrinfo	 rhints;
1233  struct addrinfo	 lhints;
1234  dk4_er_t		 er;
1235  struct addrinfo	*raddrst = NULL;
1236  struct addrinfo	*laddrst = NULL;
1237  dk4_socket_t		 back	= INVALID_SOCKET;
1238  int			 res;
1239  $? "+ dk4socket_tcp_client_for_host_num_service_app (char)"
1240#if	DK4_USE_ASSERT
1241  assert(NULL != hostname);
1242  assert(NULL != svcname);
1243#endif
1244  $? ". svcname \"%!ds\"", TR_STR(svcname)
1245  $? ". lsvcname \"%!ds\"", TR_STR(lsvcname)
1246  if ((NULL != hostname) && (NULL != svcname)) {	$? ". args ok"
1247    DK4_MEMRES(&rhints, sizeof(rhints));
1248    rhints.ai_family = AF_UNSPEC;
1249    rhints.ai_socktype = SOCK_STREAM;
1250    if (0 != nsrv) { rhints.ai_flags = AI_NUMERICSERV; }
1251    rhints.ai_protocol = 0;
1252    dk4error_init(&er);
1253    res = getaddrinfo(hostname, svcname, &rhints, &raddrst);
1254    if ((0 == res) && (NULL != raddrst)) {		$? ". remote addr ok"
1255      if (NULL != lsvcname) {				$? ". need local addr"
1256        DK4_MEMRES(&lhints, sizeof(lhints));
1257	lhints.ai_family = AF_UNSPEC;
1258	lhints.ai_socktype = SOCK_STREAM;
1259	lhints.ai_flags = AI_PASSIVE;
1260	if (0 != nsrv) { lhints.ai_flags |= AI_NUMERICSERV; }
1261	lhints.ai_protocol = 0;
1262	dk4error_init(&er);
1263	res = getaddrinfo(NULL, lsvcname, &lhints, &laddrst);
1264	if ((0 == res) && (NULL != laddrst)) {		$? ". use local addr"
1265	  back = dk4socket_tcp_client_addresses_app(
1266	    hostname, raddrst, laddrst, secs, usecs, app
1267	  );
1268	  freeaddrinfo(laddrst);
1269	} else {					$? "! no local addr"
1270	  /* ERROR: Failed to obtain local addresses (18, 19) */
1271	  dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res);
1272	  dk4socket_report_gai(NULL, lsvcname, res, 1, app, &er);
1273	}
1274      } else {						$? ". no local addr"
1275        back = dk4socket_tcp_client_addresses_app(
1276	  hostname, raddrst, NULL, secs, usecs, app
1277	);
1278      }
1279      freeaddrinfo(raddrst);
1280    } else {						$? "! remote"
1281      /* ERROR: Failed to obtain remote addresses (20, 21, 22) */
1282      dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res);
1283      dk4socket_report_gai(hostname, svcname, res, 0, app, &er);
1284    }
1285  } else {						$? "! args"
1286    /* ERROR: Invalid arguments (bug) */
1287    dk4socket_report_invalid_arguments(app);
1288  }
1289  $? "- dk4socket_tcp_client_for_host_num_service_app (char) %d", (int)back
1290  return back;
1291}
1292
1293
1294
1295dk4_socket_t
1296dk4socket_tcp_client_for_host_service_app(
1297  const	dkChar		*hostname,
1298  const	dkChar		*svcname,
1299  const dkChar		*lsvcname,
1300  long			 secs,
1301  long			 usecs,
1302  dk4_app_t		*app
1303)
1304{
1305  return (
1306    dk4socket_tcp_client_for_host_num_service_app(
1307      hostname, svcname, lsvcname, secs, usecs, 0, app
1308    )
1309  );
1310}
1311
1312
1313
1314dk4_socket_t
1315dk4socket_tcp_client_for_host_port_app(
1316  const dkChar		*hostname,
1317  unsigned short	 portno,
1318  unsigned short	 lportno,
1319  long			 secs,
1320  long			 usecs,
1321  dk4_app_t		*app
1322)
1323{
1324  char			 rpn[16*sizeof(dk4_um_t)];
1325  char			 lpn[16*sizeof(dk4_um_t)];
1326  dk4_socket_t		 back	= INVALID_SOCKET;
1327  int			 res;
1328  $? "+ dk4socket_tcp_client_for_host_port_app (char)"
1329#if	DK4_USE_ASSERT
1330  assert(NULL != hostname);
1331  assert(0 < portno);
1332#endif
1333  if ((NULL != hostname) && (0 < portno)) {
1334    res = dk4ma_write_c8_decimal_unsigned(
1335      rpn, sizeof(rpn), (dk4_um_t)portno, 0, NULL
1336    );
1337    if (0 != res) {
1338      if (0 < lportno) {
1339        res = dk4ma_write_c8_decimal_unsigned(
1340	  lpn, sizeof(lpn), (dk4_um_t)lportno, 0, NULL
1341	);
1342	if (0 != res) {
1343	  back = dk4socket_tcp_client_for_host_num_service_app(
1344	    hostname, rpn, lpn, secs, usecs, 1, app
1345	  );
1346	} else {
1347	  /* ERROR: Failed to convert port number to text, bug */
1348	}
1349      } else {
1350        back = dk4socket_tcp_client_for_host_num_service_app(
1351	  hostname, rpn, NULL, secs, usecs, 1, app
1352	);
1353      }
1354    } else {
1355      /* ERROR: Failed to convert port number to text, bug */
1356    }
1357  } else {
1358    /* ERROR: Invalid arguments (bug) */
1359    dk4socket_report_invalid_arguments(app);
1360  }
1361  $? "- dk4socket_tcp_client_for_host_port_app (char) %d", (int)back
1362  return back;
1363}
1364
1365
1366
1367/* ----- char, +getaddrinfo ----- */
1368#else
1369/* +++++ char, -getaddrinfo ----- */
1370
1371
1372
1373dk4_socket_t
1374dk4socket_tcp_client_for_host_num_service_app(
1375  const	dkChar		*hostname,
1376  const	dkChar		*svcname,
1377  const dkChar		*lsvcname,
1378  long			 secs,
1379  long			 usecs,
1380  int			 nsrv,
1381  dk4_app_t		*app
1382)
1383{
1384  const char		*endptr	= NULL;
1385  struct servent	*serv	= NULL;
1386  dk4_socket_t		 back	= INVALID_SOCKET;
1387  int			 res	= 0;
1388  int			 iport	= 0;
1389  unsigned short	 rport	= 0;
1390  unsigned short	 lport	= 0;
1391  $? "+ dk4socket_tcp_client_for_host_num_service_app (char)"
1392#if	DK4_USE_ASSERT
1393  assert(NULL != hostname);
1394  assert(NULL != svcname);
1395#endif
1396  if ((NULL != hostname) && (NULL != svcname)) {
1397    res = dk4ma_input_c8_dec_ushort(&rport, svcname, &endptr, 1, NULL);
1398    if (0 == res) {
1399      dk4socket_error_reset();
1400      serv = getservbyname(svcname, NULL);
1401      if (NULL != serv) {
1402        iport = serv->s_port;
1403	dk4socket_swap_bytes_if_not_bigendian((void *)(&iport), sizeof(iport));
1404	rport = (unsigned short)iport;
1405      } else {
1406        /* ERROR: Service name for remote port not found (23, 24) */
1407	dk4socket_report_service_not_found(app, svcname);
1408      }
1409    }
1410    if (0 != rport) {
1411      if (NULL != lsvcname) {
1412        endptr = NULL;
1413	res = dk4ma_input_c8_dec_ushort(&lport, lsvcname, &endptr, 1, NULL);
1414	if (0 == res) {
1415	  dk4socket_error_reset();
1416	  serv = getservbyname(lsvcname, NULL);
1417	  if (NULL != serv) {
1418	    iport = serv->s_port;
1419	    dk4socket_swap_bytes_if_not_bigendian(
1420	      (void *)(&iport), sizeof(iport)
1421	    );
1422	    lport = (unsigned short)iport;
1423	  } else {
1424	    /* ERROR: Service name for local port not found (23, 24) */
1425	    dk4socket_report_service_not_found(app, lsvcname);
1426	  }
1427	}
1428	if (0 != lport) {
1429	  back = dk4socket_tcp_client_for_host_port_app(
1430	    hostname, rport, lport, secs, usecs, app
1431	  );
1432	} else {
1433	  /* ERROR: Illegal local port number (28) */
1434	  dk4socket_report_invalid_port_number(app, 28);
1435	}
1436      } else {
1437        back = dk4socket_tcp_client_for_host_port_app(
1438	  hostname, rport, 0, secs, usecs, app
1439	);
1440      }
1441    } else {
1442      /* ERROR: Illegal remote port number (29) */
1443      dk4socket_report_invalid_port_number(app, 29);
1444    }
1445  } else {
1446    /* ERROR: Invalid arguments (bug) */
1447    dk4socket_report_invalid_arguments(app);
1448  }
1449  $? "- dk4socket_tcp_client_for_host_num_service_app (char) %d", (int)back
1450  return back;
1451}
1452
1453
1454
1455dk4_socket_t
1456dk4socket_tcp_client_for_host_service_app(
1457  const	dkChar		*hostname,
1458  const	dkChar		*svcname,
1459  const dkChar		*lsvcname,
1460  long			 secs,
1461  long			 usecs,
1462  dk4_app_t		*app
1463)
1464{
1465  return (
1466    dk4socket_tcp_client_for_host_num_service_app(
1467      hostname, svcname, lsvcname, secs, usecs, 0, app
1468    )
1469  );
1470}
1471
1472
1473
1474dk4_socket_t
1475dk4socket_tcp_client_for_host_port_app(
1476  const dkChar		*hostname,
1477  unsigned short	 portno,
1478  unsigned short	 lportno,
1479  long			 secs,
1480  long			 usecs,
1481  dk4_app_t		*app
1482)
1483{
1484  dk4_er_t		  er;
1485#if DK4_HAVE_STRUCT_SOCKADDR_IN6
1486  struct sockaddr_in6	  sr6;
1487  struct sockaddr_in6	  sl6;
1488#endif
1489  struct sockaddr_in	  sr4;
1490  struct sockaddr_in	  sl4;
1491  char			**addrptr;
1492  struct hostent	 *hep		= NULL;
1493  dk4_socket_t		  back		= INVALID_SOCKET;
1494  $? "+ dk4socket_tcp_client_for_host_port_app (char)"
1495#if	DK4_USE_ASSERT
1496  assert(NULL != hostname);
1497  assert(0 < portno);
1498#endif
1499  if ((NULL != hostname) && (0 < portno)) {
1500    dk4error_init(&er);
1501    dk4socket_error_reset();
1502    hep = gethostbyname(hostname);
1503    if (NULL != hep) {
1504      if (NULL != hep->h_addr_list) {
1505        switch (hep->h_addrtype) {
1506	  case AF_INET : {
1507	    if (4 == hep->h_length) {
1508	      addrptr = hep->h_addr_list;
1509	      while ((INVALID_SOCKET == back) && (NULL != *addrptr)) {
1510	        DK4_MEMRES(&sr4, sizeof(sr4));
1511		sr4.sin_family = AF_INET;
1512		sr4.sin_port   = dk4socket_htons(portno);
1513		DK4_MEMCPY(&(sr4.sin_addr), *addrptr, sizeof(IN_ADDR));
1514		dk4error_init(&er);
1515		if (0 != lportno) {
1516		  DK4_MEMRES(&sl4, sizeof(sl4));
1517		  sl4.sin_family = AF_INET;
1518		  sl4.sin_port   = dk4socket_htons(lportno);
1519		  sl4.sin_addr.s_addr = dk4socket_htonl(INADDR_ANY);
1520		  back = dk4socket_tcp_client_for_addr(
1521		    AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4),
1522		    (struct sockaddr *)(&sl4), sizeof(sl4), secs, usecs, &er
1523		  );
1524		} else {
1525		  back = dk4socket_tcp_client_for_addr(
1526		    AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4),
1527		    NULL, 0, secs, usecs, &er
1528		  );
1529		}
1530		if (INVALID_SOCKET == back) {		$? "! report failure"
1531		  /* ERROR: Failed */
1532		  dk4socket_report_connection_error(
1533		    app, AF_INET,
1534		    (struct sockaddr *)(&sr4), sizeof(sr4),
1535		    ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL),
1536		    ((0 < lportno) ? (sizeof(sl4)) : 0),
1537		    &er
1538		  );
1539		} else {
1540		  /* DEBUG: Connection established (30) */
1541		  dk4socket_report_connection_established(
1542		    app, AF_INET,
1543		    (struct sockaddr *)(&sr4), sizeof(sr4),
1544		    ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL),
1545		    ((0 < lportno) ? (sizeof(sl4)) : 0)
1546		  );
1547		}
1548	        addrptr++;
1549	      }
1550	    } else {
1551	      /* ERROR: Illegal address length (31) */
1552	      dk4socket_report_illegal_address_part(app, hostname, 31);
1553	    }
1554	  } break;
1555#if DK4_HAVE_STRUCT_SOCKADDR_IN6
1556	  case AF_INET6 : {
1557	    if (16 == hep->h_length) {
1558	      addrptr = hep->h_addr_list;
1559	      while ((INVALID_SOCKET == back) && (NULL != *addrptr)) {
1560	        DK4_MEMRES(&sr6, sizeof(sr6));
1561		sr6.sin6_family = AF_INET6;
1562		sr6.sin6_port   = dk4socket_htons(portno);
1563		DK4_MEMCPY(&(sr6.sin6_addr), *addrptr, sizeof(IN6_ADDR));
1564		dk4error_init(&er);
1565		if (0 != lportno) {
1566		  DK4_MEMRES(&sl6, sizeof(sl6));
1567		  sl6.sin6_family = AF_INET6;
1568		  sl6.sin6_port   = dk4socket_htons(lportno);
1569		  DK4_MEMCPY(&(sl6.sin6_addr),&dk4socket_any6,sizeof(IN6_ADDR));
1570		  back = dk4socket_tcp_client_for_addr(
1571		    AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6),
1572		    (struct sockaddr *)(&sl6), sizeof(sl6),
1573		    secs, usecs, &er
1574		  );
1575		} else {
1576		  back = dk4socket_tcp_client_for_addr(
1577		    AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6),
1578		    NULL, 0, secs, usecs, &er
1579		  );
1580		}
1581		if (INVALID_SOCKET == back) {		$? "! report failure"
1582		  /* ERROR: Failed */
1583		  dk4socket_report_connection_error(
1584		    app, AF_INET6,
1585		    (struct sockaddr *)(&sr6), sizeof(sr6),
1586		    ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL),
1587		    ((0 < lportno) ? (sizeof(sl6)) : 0),
1588		    &er
1589		  );
1590		} else {
1591		  /* DEBUG: Connection established (30) */
1592		  dk4socket_report_connection_established(
1593		    app, AF_INET6,
1594		    (struct sockaddr *)(&sr6), sizeof(sr6),
1595		    ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL),
1596		    ((0 < lportno) ? (sizeof(sl6)) : 0)
1597		  );
1598		}
1599	        addrptr++;
1600	      }
1601	    } else {
1602	      /* ERROR: Illegal address length (31) */
1603	      dk4socket_report_illegal_address_part(app, hostname, 31);
1604	    }
1605	  } break;
1606#endif
1607	  default : {
1608	    /* ERROR: Illegal address family (32) */
1609	    dk4socket_report_illegal_address_part(app, hostname, 32);
1610	  } break;
1611	}
1612      } else {
1613        /* ERROR: Remote host address not found! (33, 34) */
1614	dk4socket_report_host_name_problem(app, hostname, 33, 34);
1615      }
1616    } else {
1617      dk4socket_error_report(&er, DK4_E_SOCKET_GETHOSTBYNAME);
1618      /* ERROR: Remote host address not found! (33, 34) */
1619      dk4socket_report_host_name_problem(app, hostname, 33, 34);
1620    }
1621  } else {
1622    /* ERROR: Invalid arguments (bug) */
1623    dk4socket_report_invalid_arguments(app);
1624  }
1625  $? "- dk4socket_tcp_client_for_host_port_app (char) %d", (int)back
1626  return back;
1627}
1628
1629
1630
1631/* ----- char, -getaddrinfo ----- */
1632#endif
1633#endif
1634
1635