%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module #include "dk4sock.h" #include "dk4mem.h" #include "dk4maodd.h" #if !DK4_HAVE_GETADDRINFO #include "dk4rec24.h" #endif #include "dk4maiddus.h" $!trace-include #if DK4_ON_WINDOWS #if DK4_HAVE_GETADDRINFO static dk4_socket_t dk4socket_wc_tcp_client_addresses( const wchar_t *hostname, ADDRINFOW *raddrst, ADDRINFOW *laddrst, long secs, long usecs, dk4_er_t *erp ) { ADDRINFOW *ra; ADDRINFOW *la; dk4_socket_t back = INVALID_SOCKET; $? "+ dk4socket_wc_tcp_client_addresses" ra = raddrst; while ((INVALID_SOCKET == back) && (NULL != ra)) { if (NULL != laddrst) { la = laddrst; while ((INVALID_SOCKET == back) && (NULL != la)) { if (la->ai_family == ra->ai_family) { $? ". remote = %d PTR=%d %lu", (int)(ra->ai_family), TR_IPTR(ra->ai_addr), (unsigned long)(ra->ai_addrlen) $? ". local = %d PTR=%d %lu", (int)(la->ai_family), TR_IPTR(la->ai_addr), (unsigned long)(la->ai_addrlen) $!trace-code dk4socket_debug_address("remote", ra->ai_addr, ra->ai_addrlen); $!trace-code dk4socket_debug_address("local ", la->ai_addr, la->ai_addrlen); back = dk4socket_tcp_client_for_addr( ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen, secs, usecs, erp ); if (INVALID_SOCKET != back) { la = NULL; ra = NULL; } } if (NULL != la) { la = la->ai_next; } } } else { back = dk4socket_tcp_client_for_addr( ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0, secs, usecs, erp ); if (INVALID_SOCKET != back) { ra = NULL; } } if (NULL != ra) { ra = ra->ai_next; } } $? "- dk4socket_wc_tcp_client_addresses %d", (int)back return back; } #else #endif #endif dk4_socket_t dk4socket_wc_tcp_client_host_num_srv( const wchar_t *hostname, const wchar_t *svcname, const wchar_t *lsvcname, long secs, long usecs, int nsrv, dk4_er_t *erp ) { #if DK4_ON_WINDOWS #if DK4_HAVE_GETADDRINFO /* +++++ +getaddrinfo */ ADDRINFOW rhints; ADDRINFOW lhints; ADDRINFOW *raddrst = NULL; ADDRINFOW *laddrst = NULL; dk4_socket_t back = INVALID_SOCKET; int res; $? "+ dk4socket_dk_tcp_client_host_num_srv (getaddrinfo)" if ((NULL != hostname) && (NULL != svcname)) { DK4_MEMRES(&rhints, sizeof(rhints)); rhints.ai_family = AF_UNSPEC; rhints.ai_socktype = SOCK_STREAM; if (0 != nsrv) { rhints.ai_flags = AI_NUMERICSERV; } rhints.ai_protocol = 0; res = GetAddrInfoW(hostname, svcname, &rhints, &raddrst); if ((0 == res) && (NULL != raddrst)) { if (NULL != lsvcname) { DK4_MEMRES(&lhints, sizeof(lhints)); lhints.ai_family = AF_UNSPEC; lhints.ai_socktype = SOCK_STREAM; lhints.ai_flags = AI_PASSIVE; if (0 != nsrv) { lhints.ai_flags |= AI_NUMERICSERV; } lhints.ai_protocol = 0; res = GetAddrInfoW(NULL, lsvcname, &lhints, &laddrst); if ((0 == res) && (NULL != laddrst)) { back = dk4socket_wc_tcp_client_addresses( hostname, raddrst, laddrst, secs, usecs, erp ); if (NULL != laddrst) { FreeAddrInfoW(laddrst); } } else { /* ERROR: getaddrinfo failed */ dk4error_set_idetails(erp, DK4_E_SOCKET_GETADDRLOC, res); } } else { back = dk4socket_wc_tcp_client_addresses( hostname, raddrst, NULL, secs, usecs, erp ); } } else { /* ERROR: getaddrinfo failed */ dk4error_set_idetails(erp, DK4_E_SOCKET_GETADDRINFO, res); } if (NULL != laddrst) { FreeAddrInfoW(laddrst); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4socket_dk_tcp_client_host_num_srv %d", (int)back return back; /* ----- +getaddrinfo */ #else /* +++++ -getaddrinfo */ char cppt[48]; char cplp[48]; struct servent *serv = NULL; const wchar_t *endptr = NULL; dk4_socket_t back = INVALID_SOCKET; int res = 0; unsigned short rport = 0U; unsigned short lport = 0U; unsigned short iport = 0U; if ((NULL != hostname) && (NULL != svcname)) { res = dk4ma_input_dk_dec_ushort(&rport, svcname, &endptr, 1, erp); if (0 == res) { if (0 != dk4recode_wchar_t_to_char(cppt, sizeof(cppt), svcname, erp)) { dk4socket_error_reset(); serv = getservbyname(cppt, NULL); if (NULL != serv) { iport = serv->s_port; dk4socket_swap_bytes_if_not_bigendian((void *)(&iport),sizeof(iport)); rport = (unsigned short)iport; } else { dk4socket_error_report(erp, DK4_E_SOCKET_GETSERVBYNAME); } } } if (0 != rport) { if (NULL != lsvcname) { endptr = NULL; res = dk4ma_input_dk_dec_ushort(&lport, lsvcname, &endptr, 1, erp); if (0 == res) { if (0 != dk4recode_wchar_t_to_char(cplp,sizeof(cplp),lsvcname,erp)) { dk4socket_error_reset(); serv = getservbyname(cplp, NULL); if (NULL != serv) { iport = serv->s_port; dk4socket_swap_bytes_if_not_bigendian( (void *)(&iport), sizeof(iport) ); lport = (unsigned short)iport; } else { dk4socket_error_report(erp, DK4_E_SOCKET_GETSERVBYNAME); } } else { /* ERROR: Text conversion failed, already reported */ } } if (0 != lport) { back = dk4socket_wc_tcp_client_host_port( hostname, rport, lport, secs, usecs, erp ); } } else { back = dk4socket_wc_tcp_client_host_port( hostname, rport, (unsigned short)0, secs, usecs, erp ); } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; /* ----- -getaddrinfo */ #endif #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); return (DK4_SOCKET_RESULT_FAILED); #endif } dk4_socket_t dk4socket_wc_tcp_client_host_srv( const wchar_t *hostname, const wchar_t *svcname, const wchar_t *lsvcname, long secs, long usecs, dk4_er_t *erp ) { return ( dk4socket_wc_tcp_client_host_num_srv( hostname, svcname, lsvcname, secs, usecs, 0, erp ) ); } #if DK4_HAVE_STRUCT_SOCKADDR_IN6 /** used to initialize IPv6 address for binding local ports. */ static const IN6_ADDR dk4sock18_any6 = IN6ADDR_ANY_INIT ; #endif dk4_socket_t dk4socket_wc_tcp_client_host_port( const wchar_t *hostname, unsigned short portno, unsigned short lportno, long secs, long usecs, dk4_er_t *erp ) { #if DK4_ON_WINDOWS #if DK4_HAVE_GETADDRINFO /* +++++ +getaddrinfo */ wchar_t rpnb[16*sizeof(dk4_um_t)]; wchar_t lpnb[16*sizeof(dk4_um_t)]; const size_t szrpbn = DK4_SIZEOF(rpnb,wchar_t); const size_t szlpnb = DK4_SIZEOF(lpnb,wchar_t); dk4_socket_t back = INVALID_SOCKET; int res; $? "+ dk4socket_dk_tcp_client_host_port (getaddrinfo)" if ((NULL != hostname) && (0 < portno)) { res = dk4ma_write_decimal_unsigned(rpnb, szrpbn, (dk4_um_t)portno, 0, erp); if (0 != res) { if (0 < lportno) { res = dk4ma_write_decimal_unsigned(lpnb,szlpnb,(dk4_um_t)lportno,0,erp); if (0 != res) { back = dk4socket_wc_tcp_client_host_num_srv( hostname, rpnb, lpnb, secs, usecs, 1, erp ); } else { $? "! bug" } } else { back = dk4socket_wc_tcp_client_host_num_srv( hostname, rpnb, NULL, secs, usecs, 1, erp ); } } else { $? "! bug" } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4socket_dk_tcp_client_host_port %d", (int)back return back; /* ----- +getaddrinfo */ #else /* +++++ -getaddrinfo */ char hona[1040]; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 sr6; struct sockaddr_in6 sl6; #endif struct sockaddr_in sr4; struct sockaddr_in sl4; char **addrptr; struct hostent *hep; dk4_socket_t back = INVALID_SOCKET; $? "+ dk4socket_dk_tcp_client_host_port (no getaddrinfo)" if ((NULL != hostname) && (0 < portno)) { $? ". args ok" if (0 != dk4recode_wchar_t_to_char(hona, sizeof(hona), hostname, erp)) { dk4socket_error_reset(); hep = gethostbyname(hona); $? ". recode ok" if (NULL != hep) { $? ". host found" if (NULL != hep->h_addr_list) { $? ". entries in list" switch (hep->h_addrtype) { case AF_INET : { if (4 == hep->h_length) { addrptr = hep->h_addr_list; while ((INVALID_SOCKET == back) && (NULL != *addrptr)) { DK4_MEMRES(&sr4, sizeof(sr4)); sr4.sin_family = AF_INET; sr4.sin_port = dk4socket_htons(portno); DK4_MEMCPY(&(sr4.sin_addr), *addrptr, sizeof(IN_ADDR)); $!trace-code dk4socket_debug_address("remote", (struct sockaddr *)(&sr4), sizeof(sr4)); if (0 != lportno) { DK4_MEMRES(&sl4, sizeof(sl4)); sl4.sin_family = AF_INET; sl4.sin_port = dk4socket_htons(lportno); sl4.sin_addr.s_addr = dk4socket_htonl(INADDR_ANY); $!trace-code dk4socket_debug_address("local ", (struct sockaddr *)(&sl4), sizeof(sl4)); back = dk4socket_tcp_client_for_addr( AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), (struct sockaddr *)(&sl4), sizeof(sl4), secs, usecs, erp ); } else { back = dk4socket_tcp_client_for_addr( AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), NULL, 0, secs, usecs, erp ); } addrptr++; } } else { $? "! length" dk4error_set_simple_error_code(erp, DK4_E_BUG); } } break; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6 : { if (16 == hep->h_length) { addrptr = hep->h_addr_list; while ((INVALID_SOCKET == back) && (NULL != *addrptr)) { DK4_MEMRES(&sr6, sizeof(sr6)); sr6.sin6_family = AF_INET6; sr6.sin6_port = dk4socket_htons(portno); DK4_MEMCPY(&(sr6.sin6_addr), *addrptr, sizeof(IN6_ADDR)); if (0 != lportno) { DK4_MEMRES(&sl6, sizeof(sl6)); sl6.sin6_family = AF_INET6; sl6.sin6_port = dk4socket_htons(lportno); DK4_MEMCPY(&(sl6.sin6_addr), &dk4sock18_any6, sizeof(IN6_ADDR)); back = dk4socket_tcp_client_for_addr( AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), (struct sockaddr *)(&sl6), sizeof(sl6), secs, usecs, erp ); } else { back = dk4socket_tcp_client_for_addr( AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), NULL, 0, secs, usecs, erp ); } addrptr++; } } else { /* ERROR: Address length mismatch */ dk4error_set_simple_error_code(erp, DK4_E_BUG); } } break; #endif default : { /* ERROR: Unknown protocol */ dk4error_set_simple_error_code(erp, DK4_E_BUG); } break; } } else { $? "! empty list" /* ERROR: List empty */ dk4error_set_simple_error_code(erp, DK4_E_BUG); } } else { $? "! gethostbyname" /* ERROR: Host not found */ dk4socket_error_report(erp, DK4_E_SOCKET_GETHOSTBYNAME); } } else { $? "! recode" /* ERROR: Failed to convert hostname to ASCII, already reported */ } } else { $? "! args" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4socket_dk_tcp_client_host_port %d", (int)back return back; /* ----- -getaddrinfo */ #endif #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); return (DK4_SOCKET_RESULT_FAILED); #endif }