/* WARNING: This file was generated by dkct. Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk4sock17.ctr */ /* Copyright (C) 2015-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dk4sock17.c The dk4sock17 module. */ #line 10 "dk4sock17.ctr" #include "dk4sock.h" #include "dk4mem.h" #include "dk4mao8d.h" #if !DK4_HAVE_GETADDRINFO #include "dk4mai8dus.h" #endif #line 21 "dk4sock17.ctr" #if DK4_HAVE_GETADDRINFO /* +++++ +getaddrinfo +++++ */ /** Create client socket for given address lists. @param hostname Remote host name to connect to. @param raddrst List of remote addresses. @param laddrst List of local addresses to use, optional. @param secs Seconds for timeout. @param usecs Microseconds for timeout. @param erp Error report, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if any argument is bad, - DK4_E_SOCKET_SOCKET
if the socket() function failed to create a new socket, - DK4_E_SOCKET_BIND
if the bind() function failed to bind the requested local address, - DK4_E_SOCKET_FCNTL
if the fcntl() function failed, - DK4_E_SOCKET_IOCTLSOCKET if the ioctlsocket() function failed. - DK4_E_SOCKET_CONNECT
if the connect() function failed, - DK4_E_SOCKET_TIMEOUT
if a timeout occured in the connect attempt, - DK4_E_SOCKET_SELECT
if the select() function failed, - DK4_E_SOCKET_GETSOCKOPT
if the getsockopt() function failed. For all error codes - except DK4_E_SOCKET_TIMEOUT - the iDetails1 field contains the errno or WSAGetLastError() value. */ static dk4_socket_t dk4socket_c8_tcp_client_addresses( const char *hostname, struct addrinfo *raddrst, struct addrinfo *laddrst, long secs, long usecs, dk4_er_t *erp ) { struct addrinfo *ra; struct addrinfo *la; dk4_socket_t back = INVALID_SOCKET; #line 73 "dk4sock17.ctr" 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) { #line 80 "dk4sock17.ctr" #line 81 "dk4sock17.ctr" #line 82 "dk4sock17.ctr" #line 83 "dk4sock17.ctr" 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; } } #line 105 "dk4sock17.ctr" return back; } /* ----- +getaddrinfo ----- */ #else /* +++++ -getaddrinfo +++++ */ #if DK4_HAVE_STRUCT_SOCKADDR_IN6 /** used to initialize IPv6 address for binding local ports. */ static const IN6_ADDR dk4socket_any6 = IN6ADDR_ANY_INIT; #endif /* ----- -getaddrinfo ----- */ #endif dk4_socket_t dk4socket_c8_tcp_client_host_num_srv( const char *hostname, const char *svcname, const char *lsvcname, long secs, long usecs, int nsrv, dk4_er_t *erp ) { #if DK4_HAVE_GETADDRINFO /* +++++ +getaddrinfo */ struct addrinfo rhints; /* Hints for remote address */ struct addrinfo lhints; /* Hints for local address */ struct addrinfo *raddrst = NULL; /* Storage for remote addresses */ struct addrinfo *laddrst = NULL; /* Storage for local addresses */ int res; /* Operation result */ dk4_socket_t back = INVALID_SOCKET; #line 143 "dk4sock17.ctr" if ((NULL != hostname) && (NULL != svcname)) { #line 144 "dk4sock17.ctr" #line 145 "dk4sock17.ctr" 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 = getaddrinfo(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 = getaddrinfo(NULL, lsvcname, &lhints, &laddrst); if ((0 == res) && (NULL != laddrst)) { back = dk4socket_c8_tcp_client_addresses( hostname, raddrst, laddrst, secs, usecs, erp ); if (NULL != laddrst) { freeaddrinfo(laddrst); } } else { #line 166 "dk4sock17.ctr" /* ERROR: getaddrinfo failed */ dk4error_set_idetails(erp, DK4_E_SOCKET_GETADDRLOC, res); } } else { back = dk4socket_c8_tcp_client_addresses( hostname, raddrst, NULL, secs, usecs, erp ); } if (NULL != raddrst) { freeaddrinfo(raddrst); } } else { #line 176 "dk4sock17.ctr" /* ERROR: getaddrinfo failed */ dk4error_set_idetails(erp, DK4_E_SOCKET_GETADDRINFO, res); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 183 "dk4sock17.ctr" return back; /* ----- +getaddrinfo */ #else /* +++++ -getaddrinfo */ struct servent *serv = NULL; /* Service entry */ const char *endptr = NULL; /* End of used text */ int iport = 0; /* Port number from servent */ unsigned short rport = 0; /* Remote port number */ unsigned short lport = 0; /* Local port number */ int res; /* Operation result */ dk4_socket_t back = INVALID_SOCKET; #line 195 "dk4sock17.ctr" if ((NULL != hostname) && (NULL != svcname)) { #line 196 "dk4sock17.ctr" res = dk4ma_input_c8_dec_ushort(&rport, svcname, &endptr, 1, NULL); if (0 == res) { dk4socket_error_reset(); serv = getservbyname(svcname, 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_c8_dec_ushort(&lport, lsvcname, &endptr, 1, NULL); if (0 == res) { dk4socket_error_reset(); serv = getservbyname(lsvcname, 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); } } if (0 != lport) { back = dk4socket_c8_tcp_client_host_port( hostname, rport, lport, secs, usecs, erp ); } } else { back = dk4socket_c8_tcp_client_host_port( hostname, rport, (unsigned short)0, secs, usecs, erp ); } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 240 "dk4sock17.ctr" return back; /* ----- -getaddrinfo */ #endif } dk4_socket_t dk4socket_c8_tcp_client_host_srv( const char *hostname, const char *svcname, const char *lsvcname, long secs, long usecs, dk4_er_t *erp ) { return ( dk4socket_c8_tcp_client_host_num_srv( hostname, svcname, lsvcname, secs, usecs, 0, erp ) ); } dk4_socket_t dk4socket_c8_tcp_client_host_port( const char *hostname, unsigned short portno, unsigned short lportno, long secs, long usecs, dk4_er_t *erp ) { #if DK4_HAVE_GETADDRINFO /* +++++ +getaddrinfo */ char rpnb[16*sizeof(dk4_um_t)]; /* Remote port no */ char lpnb[16*sizeof(dk4_um_t)]; /* Local port no */ int res; dk4_socket_t back = INVALID_SOCKET; #line 283 "dk4sock17.ctr" if ((NULL != hostname) && (0 < portno)) { res = dk4ma_write_c8_decimal_unsigned( rpnb, sizeof(rpnb), (dk4_um_t)portno, 0, erp ); if (0 != res) { if (0 < lportno) { res = dk4ma_write_c8_decimal_unsigned( lpnb, sizeof(lpnb), (dk4_um_t)lportno, 0, erp ); if (0 != res) { back = dk4socket_c8_tcp_client_host_num_srv( hostname, rpnb, lpnb, secs, usecs, 1, erp ); } else { #line 297 "dk4sock17.ctr" } } else { back = dk4socket_c8_tcp_client_host_num_srv( hostname, rpnb, NULL, secs, usecs, 1, erp ); } } else { #line 304 "dk4sock17.ctr" } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; /* ----- -getaddrinfo */ /* ----- +getaddrinfo */ #else /* +++++ -getaddrinfo */ #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 = NULL; dk4_socket_t back = INVALID_SOCKET; #line 323 "dk4sock17.ctr" if ((NULL != hostname) && (0 < portno)) { hep = gethostbyname(hostname); if (NULL != hep) { #line 326 "dk4sock17.ctr" if (NULL != hep->h_addr_list) { #line 327 "dk4sock17.ctr" switch (hep->h_addrtype) { case AF_INET : { #line 329 "dk4sock17.ctr" if (4 == hep->h_length) { #line 330 "dk4sock17.ctr" 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)); #line 337 "dk4sock17.ctr" 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); #line 343 "dk4sock17.ctr" 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 { #line 357 "dk4sock17.ctr" /* ERROR: Address length mismatch */ dk4error_set_simple_error_code(erp, DK4_E_BUG); } } break; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6 : { #line 363 "dk4sock17.ctr" 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), &dk4socket_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 { #line 400 "dk4sock17.ctr" /* ERROR: Host not found (empty list) */ dk4error_set_simple_error_code(erp, DK4_E_BUG); } } else { #line 404 "dk4sock17.ctr" /* ERROR: Host not found */ dk4socket_error_report(erp, DK4_E_SOCKET_GETHOSTBYNAME); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; /* ----- -getaddrinfo */ #endif }