%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module #include "dk4sock.h" #include "dk4socka.h" #include "dk4mem.h" #if DK4_HAVE_GETADDRINFO #include "dk4mao8d.h" #else #if DK4_CHAR_SIZE > 1 #include "dk4maiwdus.h" #include "dk4rec24.h" #endif #include "dk4mai8dus.h" #endif #include "dk4maiddus.h" #include "dk4maodd.h" #include "dk4maodh.h" $!trace-include /** Constant texts used by module, not localized. */ static const dkChar * const dk4socket_03_kwnl[] = { $!string-table macro=dkT # # 0 Separator to switch to next line. # \n\t # # 1 Separator between function name and message text # : # # 2 Separator between service and host name # @ $!end }; /* Internal tool functions ----------------------- */ /** Report error from dk4socket_tcp_client_for_addr(). @param app Application structure for logging. @param hostname Host name to connect to. @param afam Address family. @param sremote Pointer to remote address buffer. @param szremote Remote address size. @param slocal Pointer to local address buffer. @param szlocal Local address size. @param erp Error report, required. */ static void dk4socket_report_connection_error( dk4_app_t *app, const dkChar *hostname, int afam, const struct sockaddr *sremote, size_t szremote, const struct sockaddr *slocal, size_t szlocal, dk4_er_t *erp ) { const dkChar * msgt[32]; /* Message components */ dkChar bdec[16*sizeof(dk4_um_t)]; /* Decimal */ dkChar bhex[16*sizeof(dk4_um_t)]; /* Hexadecimal */ dkChar bloc[128]; /* Local address */ dkChar brem[128]; /* Remote address */ const dkChar * const *msga = NULL; /* Localized texts */ const dkChar *fctname = NULL; /* Name of failed function */ const dkChar *msgtext = NULL; /* Text why fct failed */ #if VERSION_BEFORE_20150821 size_t szmsga = 0; /* Number of elems in msga */ #endif size_t used = 0; /* No used elems in msgt */ int res = 0; /* Conversion result */ int bothbuf = 0; /* Flag: Have bdec and bhex */ int fctnmsg = 0; /* Flag: Use fct name */ $? "+ dk4socket_report_connection_error" if (NULL != app) { if (dk4app_log_do(app, DK4_LL_ERROR)) { #if VERSION_BEFORE_20150821 szmsga = dk4socket_log_num_texts(); #endif msga = dk4socket_log_texts(app); dk4socket_log_fctname_msg(&fctname, &msgtext, app, erp); if (NULL == msgtext) { res = dk4ma_write_decimal_signed( bdec, DK4_SIZEOF(bdec,dkChar), (dk4_im_t)(erp->dt.iDetails1), 0, NULL ); if (0 != res) { res = dk4ma_write_hex_signed( bhex,DK4_SIZEOF(bhex,dkChar),(dk4_im_t)(erp->dt.iDetails1),0,NULL ); if (0 != res) { bothbuf = 1; } } } msgt[used++] = msga[41]; if ((NULL != slocal) && (0 < szlocal)) { res = dk4socket_addr_port_to_text( bloc, DK4_SIZEOF(bloc,dkChar), afam, slocal, szlocal, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[42]; msgt[used++] = bloc; } } if ((NULL != sremote) && (0 < szremote)) { res = dk4socket_addr_port_to_text( brem, DK4_SIZEOF(brem,dkChar), afam, sremote, szremote, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[43]; msgt[used++] = brem; } } switch (erp->ec) { case DK4_E_INVALID_ARGUMENTS : { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[45]; } break; case DK4_E_SOCKET_SOCKET : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[2]; } break; case DK4_E_SOCKET_BIND : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[4]; } break; case DK4_E_SOCKET_FCNTL : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[9]; } break; case DK4_E_SOCKET_IOCTLSOCKET : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[9]; } break; case DK4_E_SOCKET_CONNECT : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[7]; } break; case DK4_E_SOCKET_TIMEOUT : { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[44]; } break; case DK4_E_SOCKET_SELECT : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[44]; } break; case DK4_E_SOCKET_GETSOCKOPT : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[8]; } break; case DK4_E_SOCKET_SETSOCKOPT : { fctnmsg = 1; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[8]; } break; } if (0 != fctnmsg) { if ((NULL != fctname) && ((NULL != msgtext) || (0 != bothbuf))) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = fctname; msgt[used++] = dk4socket_03_kwnl[1]; if (NULL != msgtext) { msgt[used++] = msgtext; } else { #if DK4_ON_WINDOWS msgt[used++] = msga[40]; #else msgt[used++] = msga[37]; #endif msgt[used++] = bdec; msgt[used++] = msga[38]; msgt[used++] = bhex; msgt[used++] = msga[39]; } } } dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } $? "- dk4socket_report_connection_error" } /** Report error from dk4socket_tcp_client_for_addr(). @param app Application structure for logging. @param hostname Host name to connect to. @param afam Address family. @param sremote Pointer to remote address buffer. @param szremote Remote address size. @param slocal Pointer to local address buffer. @param szlocal Local address size. @param erp Error report, required. */ static void dk4socket_report_connection_established( dk4_app_t *app, const dkChar *hostname, int afam, const struct sockaddr *sremote, size_t szremote, const struct sockaddr *slocal, size_t szlocal ) { const dkChar * msgt[32]; /* Message components */ dkChar bloc[128]; /* Local address */ dkChar brem[128]; /* Remote address */ const dkChar * const *msga = NULL; /* Localized texts */ #if VERSION_BEFORE_20150821 size_t szmsga = 0; /* Number of elems in msga */ #endif size_t used = 0; /* No used elems in msgt */ int res = 0; /* Conversion result */ if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_PROGRESS)) { #if VERSION_BEFORE_20150821 szmsga = dk4socket_log_num_texts(); #endif msga = dk4socket_log_texts(app); msgt[used++] = msga[30]; if ((NULL != slocal) && (0 < szlocal)) { res = dk4socket_addr_port_to_text( bloc, DK4_SIZEOF(bloc,dkChar), afam, slocal, szlocal, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[42]; msgt[used++] = bloc; } } if ((NULL != sremote) && (0 < szremote)) { res = dk4socket_addr_port_to_text( brem, DK4_SIZEOF(brem,dkChar), afam, sremote, szremote, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[43]; msgt[used++] = brem; } } dk4app_log_msg(app, DK4_LL_PROGRESS, msgt, used); } } } static void dk4socket_report_invalid_arguments( dk4_app_t *app ) { const dkChar * msgt[16]; const dkChar * const *msga; #if VERSION_BEFORE_20150821 size_t szmsga; #endif size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { #if VERSION_BEFORE_20150821 szmsga = dk4socket_log_num_texts(); #endif msga = dk4socket_log_texts(app); msgt[used++] = msga[41]; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[45]; dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } #if DK4_HAVE_GETADDRINFO /* +++++ +getaddrinfo +++++ */ static void dk4socket_report_no_matching_addresses( const dkChar *hostname, dk4_app_t *app ) { const dkChar *msgt[16]; const dkChar * const *msga; #if VERSION_BEFORE_20150821 size_t szmsga; #endif if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { #if VERSION_BEFORE_20150821 szmsga = dk4socket_log_num_texts(); #endif msga = dk4socket_log_texts(app); msgt[0] = msga[41]; msgt[1] = dk4socket_03_kwnl[0]; msgt[2] = msga[43]; msgt[4] = hostname; msgt[5] = dk4socket_03_kwnl[0]; msgt[6] = msga[46]; dk4app_log_msg(app, DK4_LL_ERROR, msgt, 7); } } } static void dk4socket_report_gai( const dkChar *hostname, const dkChar *lsvcname, int res, int local, dk4_app_t *app, dk4_er_t *erp ) { dkChar bdec[16*sizeof(dk4_um_t)]; dkChar bhex[16*sizeof(dk4_um_t)]; const dkChar *msgt[16]; const dkChar * const *msga; const dkChar *fctname = NULL; const dkChar *msgtext = NULL; #if VERSION_BEFORE_20150821 size_t szmsga; #endif size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { #if VERSION_BEFORE_20150821 szmsga = dk4socket_log_num_texts(); #endif msga = dk4socket_log_texts(app); dk4socket_log_fctname_msg(&fctname, &msgtext, app, erp); msgt[used++] = msga[41]; if ((NULL != hostname) && (0 == local)) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[20]; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[21]; msgt[used++] = hostname; if (NULL != lsvcname) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[22]; msgt[used++] = lsvcname; } } else { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[18]; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[19]; msgt[used++] = lsvcname; } if (NULL != fctname) { if (NULL != msgtext) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = fctname; msgt[used++] = dk4socket_03_kwnl[1]; msgt[used++] = msgtext; } else { res = dk4ma_write_decimal_signed( bdec,DK4_SIZEOF(bdec,dkChar),(dk4_im_t)(erp->dt.iDetails1),0,NULL ); if (0 != res) { res = dk4ma_write_hex_signed( bhex,DK4_SIZEOF(bhex,dkChar),(dk4_im_t)(erp->dt.iDetails1),0,NULL ); if (0 != res) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = fctname; msgt[used++] = dk4socket_03_kwnl[1]; #if DK4_ON_WINDOWS msgt[used++] = msga[40]; #else msgt[used++] = msga[37]; #endif msgt[used++] = bdec; msgt[used++] = msga[38]; msgt[used++] = bhex; msgt[used++] = msga[39]; } } } } else { } dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } #if DK4_CHAR_SIZE > 1 /** Create a socket using remote and optionally local address lists. @param hostname Remote host name. @param rast List of remote addresses. @param last List of local addresses, may be NULL. @param secs Seconds for timeout. @param usecs Microseconds for timeout. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ static dk4_socket_t dk4socket_tcp_client_addresses_app( const dkChar *hostname, ADDRINFOW *rast, ADDRINFOW *last, long secs, long usecs, dk4_app_t *app ) { dk4_er_t er; ADDRINFOW *ra; ADDRINFOW *la; dk4_socket_t back = INVALID_SOCKET; int mpf = 0; $? "+ dk4socket_tcp_client_addresses_app %d %d", TR_IPTR(rast), TR_IPTR(last) ra = rast; while ((INVALID_SOCKET == back) && (NULL != ra)) { if (NULL != last) { la = last; while ((INVALID_SOCKET == back) && (NULL != la)) { if (ra->ai_family == la->ai_family) { mpf = 1; $? ". families match, attempt to connect" dk4error_init(&er); back = dk4socket_tcp_client_for_addr( ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen, secs, usecs, &er ); if (INVALID_SOCKET != back) { dk4socket_report_connection_established( app, hostname, ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen ); ra = NULL; la = NULL; } else { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app, hostname, ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen, &er ); } } if (NULL != la) { la = la->ai_next; } } } else { mpf = 1; dk4error_init(&er); back = dk4socket_tcp_client_for_addr( ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0, secs, usecs, &er ); if (INVALID_SOCKET != back) { dk4socket_report_connection_established( app, hostname, ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0 ); ra = NULL; } else { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app,hostname,ra->ai_family,ra->ai_addr,ra->ai_addrlen,NULL,0,&er ); } } if (NULL != ra) { ra = ra->ai_next; } } if (INVALID_SOCKET == back) { if (0 == mpf) { $? ". report no matching families" /* ERROR: No matching address pair found (27) */ dk4socket_report_no_matching_addresses(hostname, app); } } $? "- dk4socket_tcp_client_addresses_app %d", (int)back return back; } #else /** Create a socket using remote and optionally local address lists. @param hostname Remote host name. @param rast List of remote addresses. @param last List of local addresses, may be NULL. @param secs Seconds for timeout. @param usecs Microseconds for timeout. @param app Application structure for diagnostics, may be NULL. @return Valid socket on success, INVALID_SOCKET on error. */ static dk4_socket_t dk4socket_tcp_client_addresses_app( const dkChar *hostname, struct addrinfo *rast, struct addrinfo *last, long secs, long usecs, dk4_app_t *app ) { dk4_er_t er; struct addrinfo *ra; struct addrinfo *la; dk4_socket_t back = INVALID_SOCKET; int mpf = 0; $? "+ dk4socket_tcp_client_addresses_app %d %d", TR_IPTR(rast), TR_IPTR(last) ra = rast; while ((INVALID_SOCKET == back) && (NULL != ra)) { if (NULL != last) { la = last; while ((INVALID_SOCKET == back) && (NULL != la)) { if (ra->ai_family == la->ai_family) { mpf = 1; dk4error_init(&er); back = dk4socket_tcp_client_for_addr( ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen, secs, usecs, &er ); if (INVALID_SOCKET != back) { dk4socket_report_connection_established( app, hostname, ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen ); ra = NULL; la = NULL; } else { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app, hostname, ra->ai_family, ra->ai_addr, ra->ai_addrlen, la->ai_addr, la->ai_addrlen, &er ); } } if (NULL != la) { la = la->ai_next; } } } else { mpf = 1; dk4error_init(&er); back = dk4socket_tcp_client_for_addr( ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0, secs, usecs, &er ); if (INVALID_SOCKET != back) { dk4socket_report_connection_established( app, hostname, ra->ai_family, ra->ai_addr, ra->ai_addrlen, NULL, 0 ); ra = NULL; } else { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app,hostname,ra->ai_family,ra->ai_addr,ra->ai_addrlen,NULL,0,&er ); } } if (NULL != ra) { ra = ra->ai_next; } } if (INVALID_SOCKET == back) { if (0 == mpf) { /* ERROR: No matching address pair found (27) */ dk4socket_report_no_matching_addresses(hostname, app); } } $? "- dk4socket_tcp_client_addresses_app %d", (int)back return back; } #endif /* ----- +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 static void dk4socket_report_invalid_port_number(dk4_app_t *app, size_t i) { const dkChar * msgt[16]; const dkChar * const *msga; size_t szmsga; size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { szmsga = dk4socket_log_num_texts(); msga = dk4socket_log_texts(app); msgt[used++] = msga[41]; msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[i]; dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } static void dk4socket_report_service_not_found(dk4_app_t *app, const dkChar *svcname) { const dkChar * msgt[16]; const dkChar * const *msga; size_t szmsga; size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { szmsga = dk4socket_log_num_texts(); msga = dk4socket_log_texts(app); msgt[used++] = msga[23]; msgt[used++] = svcname; msgt[used++] = msga[24]; dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } #if DK4_CHAR_SIZE > 1 static void dk4socket_report_service_not_ascii(dk4_app_t *app, const dkChar *svcname) { const dkChar * msgt[16]; const dkChar * const *msga; size_t szmsga; size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { szmsga = dk4socket_log_num_texts(); msga = dk4socket_log_texts(app); msgt[used++] = msga[25]; msgt[used++] = svcname; msgt[used++] = msga[26]; dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } #endif static void dk4socket_report_illegal_address_part( dk4_app_t *app, const dkChar *hostname, size_t i ) { const dkChar * msgt[16]; const dkChar * const *msga; size_t szmsga; size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { szmsga = dk4socket_log_num_texts(); msga = dk4socket_log_texts(app); msgt[used++] = msga[i]; if (NULL != hostname) { msgt[used++] = dk4socket_03_kwnl[0]; msgt[used++] = msga[43]; msgt[used++] = hostname; } dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } static void dk4socket_report_host_name_problem( dk4_app_t *app, const dkChar *hostname, size_t i1, size_t i2 ) { const dkChar * msgt[16]; const dkChar * const *msga; size_t szmsga; size_t used = 0; if (NULL != app) { if (0 != dk4app_log_do(app, DK4_LL_ERROR)) { szmsga = dk4socket_log_num_texts(); msga = dk4socket_log_texts(app); if (NULL != hostname) { msgt[used++] = msga[i1]; msgt[used++] = hostname; msgt[used++] = msga[i2]; } dk4app_log_msg(app, DK4_LL_ERROR, msgt, used); } } } /* ----- -getaddrinfo ----- */ #endif /* Exported functions ------------------ */ #if DK4_CHAR_SIZE > 1 #if DK4_ON_WINDOWS #if DK4_HAVE_GETADDRINFO /* +++++ wchar_t (Windows), +getaddrinfo +++++ */ dk4_socket_t dk4socket_tcp_client_for_host_num_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, int nsrv, dk4_app_t *app ) { ADDRINFOW rhints; ADDRINFOW lhints; dk4_er_t er; ADDRINFOW *rast = NULL; ADDRINFOW *last = NULL; dk4_socket_t back = INVALID_SOCKET; int res; $? "+ dk4socket_tcp_client_for_host_num_service_app (wchar_t +getaddrinfo)" if ((NULL != hostname) && (NULL != svcname)) { $? ". args ok" 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; dk4error_init(&er); res = GetAddrInfoW(hostname, svcname, &rhints, &rast); if ((0 == res) && (NULL != rast)) { $? ". getaddrinfo (remote)" if (NULL != lsvcname) { $? ". local service name" 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; dk4error_init(&er); res = GetAddrInfoW(NULL, lsvcname, &lhints, &last); if ((0 == res) && (NULL != last)) { $? ". getaddrinfo local" back = dk4socket_tcp_client_addresses_app( hostname, rast, last, secs, usecs, app ); FreeAddrInfoW(last); } else { $? "! getaddrinfo local" /* ERROR: Failed to obtain local addresses to bind (18, 19) */ dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res); dk4socket_report_gai(NULL, lsvcname, res, 1, app, &er); } } else { $? ". no local service name" back = dk4socket_tcp_client_addresses_app( hostname, rast, NULL, secs, usecs, app ); } FreeAddrInfoW(rast); } else { $? "! getaddrinfo (remote)" /* ERROR: Failed to obtain remote addresses (20, 21, 22) */ dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res); dk4socket_report_gai(hostname, svcname, res, 0, app, &er); } } else { $? "! args" /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_num_service_app (wchar_t) %d", (int)back return back; } dk4_socket_t dk4socket_tcp_client_for_host_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, dk4_app_t *app ) { return ( dk4socket_tcp_client_for_host_num_service_app( hostname, svcname, lsvcname, secs, usecs, 0, app ) ); } dk4_socket_t dk4socket_tcp_client_for_host_port_app( const dkChar *hostname, unsigned short portno, unsigned short lportno, long secs, long usecs, dk4_app_t *app ) { dkChar rpnb[16*sizeof(dk4_um_t)]; dkChar lpnb[16*sizeof(dk4_um_t)]; dk4_er_t er; dk4_socket_t back = INVALID_SOCKET; int res; $? "+ dk4socket_tcp_client_for_host_port_app (wchar_t)" if ((NULL != hostname) && (0 < portno)) { $? ". args ok" dk4error_init(&er); res = dk4ma_write_decimal_unsigned( rpnb, DK4_SIZEOF(rpnb,dkChar), (dk4_um_t)portno, 0, &er ); if (0 != res) { $? ". num to text" if (0 < lportno) { $? ". local port" dk4error_init(&er); res = dk4ma_write_decimal_unsigned( lpnb, DK4_SIZEOF(lpnb,dkChar), (dk4_um_t)lportno, 0, &er ); if (0 != res) { $? ". num to text" back = dk4socket_tcp_client_for_host_num_service_app( hostname, rpnb, lpnb, secs, usecs, 0, app ); } else { $? "! bug" /* ERROR: Failed to convert local port number to text, bug */ } } else { $? ". no local port" back = dk4socket_tcp_client_for_host_num_service_app( hostname, rpnb, NULL, secs, usecs, 0, app ); } } else { $? "! num to text" /* ERROR: Failed to convert port number to text, bug */ } } else { $? "! args" /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_port_app (wchar_t) %d", (int)back return back; } /* ----- wchar_t (Windows), +getaddrinfo ----- */ #else /* +++++ wchar_t (Windows), -getaddrinfo +++++ */ dk4_socket_t dk4socket_tcp_client_for_host_num_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, int nsrv, dk4_app_t *app ) { char cppt[48]; char cplp[48]; dk4_er_t er; struct servent *serv = NULL; const dkChar *endptr = NULL; dk4_socket_t back = INVALID_SOCKET; int res = 0; unsigned short rport = 0U; unsigned short lport = 0U; unsigned short iport = 0U; $? "+ dk4socket_tcp_client_for_host_num_service_app (wchar_t)" if ((NULL != hostname) && (NULL != svcname)) { dk4error_init(&er); res = dk4ma_input_dk_dec_ushort(&rport, svcname, &endptr, 1, NULL); if (0 == res) { if (0 != dk4recode_wchar_t_to_char(cppt, sizeof(cppt), svcname, &er)) { 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(&er, DK4_E_SOCKET_GETSERVBYNAME); /* ERROR: Service not found (23, 24) */ dk4socket_report_service_not_found(app, svcname); } } else { /* ERROR: Failed to convert service name (25, 26) */ dk4socket_report_service_not_ascii(app, svcname); } } if (0 < rport) { if (NULL != lsvcname) { endptr = NULL; dk4error_init(&er); res = dk4ma_input_dk_dec_ushort(&lport, lsvcname, &endptr, 1, NULL); if (0 == res) { dk4error_init(&er); if (0 != dk4recode_wchar_t_to_char(cplp,sizeof(cplp),lsvcname,&er)) { 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(&er, DK4_E_SOCKET_GETSERVBYNAME); /* Service not found (23, 24) */ dk4socket_report_service_not_found(app, lsvcname); } } else { /* ERROR: Text conversion failed (25, 26) */ dk4socket_report_service_not_ascii(app, lsvcname); } } if (0 < lport) { back = dk4socket_tcp_client_for_host_port_app( hostname, rport, lport, secs, usecs, app ); } else { /* ERROR: Illegal local port number (28) */ dk4socket_report_invalid_port_number(app, 28); } } else { back = dk4socket_tcp_client_for_host_port_app( hostname, rport, 0, secs, usecs, app ); } } else { /* ERROR: Illegal remote port number (29) */ dk4socket_report_invalid_port_number(app, 29); } } else { /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_num_service_app (wchar_t) %d", (int)back return back; } dk4_socket_t dk4socket_tcp_client_for_host_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, dk4_app_t *app ) { return ( dk4socket_tcp_client_for_host_num_service_app( hostname, svcname, lsvcname, secs, usecs, 0, app ) ); } dk4_socket_t dk4socket_tcp_client_for_host_port_app( const dkChar *hostname, unsigned short portno, unsigned short lportno, long secs, long usecs, dk4_app_t *app ) { 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; dk4_er_t er; char **addrptr; struct hostent *hep; dk4_socket_t back = INVALID_SOCKET; $? "+ dk4socket_tcp_client_for_host_port_app (wchar_t)" if ((NULL != hostname) && (0 < portno)) { dk4error_init(&er); if (0 != dk4recode_wchar_t_to_char(hona, sizeof(hona), hostname, &er)) { dk4socket_error_reset(); hep = gethostbyname(hona); if (NULL != hep) { if (NULL != hep->h_addr_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)); dk4error_init(&er); 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); back = dk4socket_tcp_client_for_addr( AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), (struct sockaddr *)(&sl4), sizeof(sl4), secs, usecs, &er ); } else { back = dk4socket_tcp_client_for_addr( AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), NULL, 0, secs, usecs, &er ); } if (INVALID_SOCKET == back) { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app, hostname, AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL), ((0 < lportno) ? (sizeof(sl4)) : 0), &er ); } else { /* DEBUG: Connection established (30) */ dk4socket_report_connection_established( app, hostname, AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL), ((0 < lportno) ? (sizeof(sl4)) : 0) ); } addrptr++; } } else { /* ERROR: Illegal address length, bug (31) */ dk4socket_report_illegal_address_part(app, hostname, 31); } } 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)); dk4error_init(&er); 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, &er ); } else { back = dk4socket_tcp_client_for_addr( AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), NULL, 0, secs, usecs, &er ); } if (INVALID_SOCKET == back) { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app, hostname, AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL), ((0 < lportno) ? (sizeof(sl6)) : 0), &er ); } else { /* DEBUG: Connection established (30) */ dk4socket_report_connection_established( app, hostname, AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL), ((0 < lportno) ? (sizeof(sl6)) : 0) ); } addrptr++; } } else { /* ERROR: Illegal address length, bug (31) */ dk4socket_report_illegal_address_part(app, hostname, 31); } } break; #endif default : { /* ERROR: Illegal address family (32) */ dk4socket_report_illegal_address_part(app, hostname, 32); } break; } } else { /* ERROR: Host not found (33, 34) */ dk4socket_report_host_name_problem(app, hostname, 33, 34); } } else { dk4socket_error_report(&er, DK4_E_SOCKET_GETHOSTBYNAME); /* ERROR: Host not found (33, 34) */ dk4socket_report_host_name_problem(app, hostname, 33, 34); } } else { /* ERROR: Failed to convert host name to ASCII (35, 36) */ dk4socket_report_host_name_problem(app, hostname, 35, 36); } } else { /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_port_app (wchar_t) %d", (int)back return back; } /* ----- wchar_t (Windows), -getaddrinfo ----- */ #endif #else #error No support for networking with wchar_t strings! #endif #else #if DK4_HAVE_GETADDRINFO /* +++++ char, +getaddrinfo +++++ */ dk4_socket_t dk4socket_tcp_client_for_host_num_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, int nsrv, dk4_app_t *app ) { struct addrinfo rhints; struct addrinfo lhints; dk4_er_t er; struct addrinfo *raddrst = NULL; struct addrinfo *laddrst = NULL; dk4_socket_t back = INVALID_SOCKET; int res; $? "+ dk4socket_tcp_client_for_host_num_service_app (char)" $? ". svcname \"%!ds\"", TR_STR(svcname) $? ". lsvcname \"%!ds\"", TR_STR(lsvcname) if ((NULL != hostname) && (NULL != svcname)) { $? ". args ok" 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; dk4error_init(&er); res = getaddrinfo(hostname, svcname, &rhints, &raddrst); if ((0 == res) && (NULL != raddrst)) { $? ". remote addr ok" if (NULL != lsvcname) { $? ". need local addr" 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; dk4error_init(&er); res = getaddrinfo(NULL, lsvcname, &lhints, &laddrst); if ((0 == res) && (NULL != laddrst)) { $? ". use local addr" back = dk4socket_tcp_client_addresses_app( hostname, raddrst, laddrst, secs, usecs, app ); freeaddrinfo(laddrst); } else { $? "! no local addr" /* ERROR: Failed to obtain local addresses (18, 19) */ dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res); dk4socket_report_gai(NULL, lsvcname, res, 1, app, &er); } } else { $? ". no local addr" back = dk4socket_tcp_client_addresses_app( hostname, raddrst, NULL, secs, usecs, app ); } freeaddrinfo(raddrst); } else { $? "! remote" /* ERROR: Failed to obtain remote addresses (20, 21, 22) */ dk4error_set_idetails(&er, DK4_E_SOCKET_GETADDRINFO, res); dk4socket_report_gai(hostname, svcname, res, 0, app, &er); } } else { $? "! args" /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_num_service_app (char) %d", (int)back return back; } dk4_socket_t dk4socket_tcp_client_for_host_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, dk4_app_t *app ) { return ( dk4socket_tcp_client_for_host_num_service_app( hostname, svcname, lsvcname, secs, usecs, 0, app ) ); } dk4_socket_t dk4socket_tcp_client_for_host_port_app( const dkChar *hostname, unsigned short portno, unsigned short lportno, long secs, long usecs, dk4_app_t *app ) { char rpn[16*sizeof(dk4_um_t)]; char lpn[16*sizeof(dk4_um_t)]; dk4_socket_t back = INVALID_SOCKET; int res; $? "+ dk4socket_tcp_client_for_host_port_app (char)" if ((NULL != hostname) && (0 < portno)) { res = dk4ma_write_c8_decimal_unsigned( rpn, sizeof(rpn), (dk4_um_t)portno, 0, NULL ); if (0 != res) { if (0 < lportno) { res = dk4ma_write_c8_decimal_unsigned( lpn, sizeof(lpn), (dk4_um_t)lportno, 0, NULL ); if (0 != res) { back = dk4socket_tcp_client_for_host_num_service_app( hostname, rpn, lpn, secs, usecs, 1, app ); } else { /* ERROR: Failed to convert port number to text, bug */ } } else { back = dk4socket_tcp_client_for_host_num_service_app( hostname, rpn, NULL, secs, usecs, 1, app ); } } else { /* ERROR: Failed to convert port number to text, bug */ } } else { /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_port_app (char) %d", (int)back return back; } /* ----- char, +getaddrinfo ----- */ #else /* +++++ char, -getaddrinfo ----- */ dk4_socket_t dk4socket_tcp_client_for_host_num_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, int nsrv, dk4_app_t *app ) { const char *endptr = NULL; struct servent *serv = NULL; dk4_socket_t back = INVALID_SOCKET; int res = 0; int iport = 0; unsigned short rport = 0; unsigned short lport = 0; $? "+ dk4socket_tcp_client_for_host_num_service_app (char)" if ((NULL != hostname) && (NULL != svcname)) { 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 { /* ERROR: Service name for remote port not found (23, 24) */ dk4socket_report_service_not_found(app, svcname); } } 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 { /* ERROR: Service name for local port not found (23, 24) */ dk4socket_report_service_not_found(app, lsvcname); } } if (0 != lport) { back = dk4socket_tcp_client_for_host_port_app( hostname, rport, lport, secs, usecs, app ); } else { /* ERROR: Illegal local port number (28) */ dk4socket_report_invalid_port_number(app, 28); } } else { back = dk4socket_tcp_client_for_host_port_app( hostname, rport, 0, secs, usecs, app ); } } else { /* ERROR: Illegal remote port number (29) */ dk4socket_report_invalid_port_number(app, 29); } } else { /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_num_service_app (char) %d", (int)back return back; } dk4_socket_t dk4socket_tcp_client_for_host_service_app( const dkChar *hostname, const dkChar *svcname, const dkChar *lsvcname, long secs, long usecs, dk4_app_t *app ) { return ( dk4socket_tcp_client_for_host_num_service_app( hostname, svcname, lsvcname, secs, usecs, 0, app ) ); } dk4_socket_t dk4socket_tcp_client_for_host_port_app( const dkChar *hostname, unsigned short portno, unsigned short lportno, long secs, long usecs, dk4_app_t *app ) { dk4_er_t er; #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; $? "+ dk4socket_tcp_client_for_host_port_app (char)" if ((NULL != hostname) && (0 < portno)) { dk4error_init(&er); dk4socket_error_reset(); hep = gethostbyname(hostname); if (NULL != hep) { if (NULL != hep->h_addr_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)); dk4error_init(&er); 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); back = dk4socket_tcp_client_for_addr( AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), (struct sockaddr *)(&sl4), sizeof(sl4), secs, usecs, &er ); } else { back = dk4socket_tcp_client_for_addr( AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), NULL, 0, secs, usecs, &er ); } if (INVALID_SOCKET == back) { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app, hostname, AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL), ((0 < lportno) ? (sizeof(sl4)) : 0), &er ); } else { /* DEBUG: Connection established (30) */ dk4socket_report_connection_established( app, hostname, AF_INET, (struct sockaddr *)(&sr4), sizeof(sr4), ((0 < lportno) ? ((struct sockaddr *)(&sl4)) : NULL), ((0 < lportno) ? (sizeof(sl4)) : 0) ); } addrptr++; } } else { /* ERROR: Illegal address length (31) */ dk4socket_report_illegal_address_part(app, hostname, 31); } } 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)); dk4error_init(&er); 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, &er ); } else { back = dk4socket_tcp_client_for_addr( AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), NULL, 0, secs, usecs, &er ); } if (INVALID_SOCKET == back) { $? "! report failure" /* ERROR: Failed */ dk4socket_report_connection_error( app, hostname, AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL), ((0 < lportno) ? (sizeof(sl6)) : 0), &er ); } else { /* DEBUG: Connection established (30) */ dk4socket_report_connection_established( app, hostname, AF_INET6, (struct sockaddr *)(&sr6), sizeof(sr6), ((0 < lportno) ? ((struct sockaddr *)(&sl6)) : NULL), ((0 < lportno) ? (sizeof(sl6)) : 0) ); } addrptr++; } } else { /* ERROR: Illegal address length (31) */ dk4socket_report_illegal_address_part(app, hostname, 31); } } break; #endif default : { /* ERROR: Illegal address family (32) */ dk4socket_report_illegal_address_part(app, hostname, 32); } break; } } else { /* ERROR: Remote host address not found! (33, 34) */ dk4socket_report_host_name_problem(app, hostname, 33, 34); } } else { dk4socket_error_report(&er, DK4_E_SOCKET_GETHOSTBYNAME); /* ERROR: Remote host address not found! (33, 34) */ dk4socket_report_host_name_problem(app, hostname, 33, 34); } } else { /* ERROR: Invalid arguments (bug) */ dk4socket_report_invalid_arguments(app); } $? "- dk4socket_tcp_client_for_host_port_app (char) %d", (int)back return back; } /* ----- char, -getaddrinfo ----- */ #endif #endif