diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dk4sock16.ctr |
Initial commit
Diffstat (limited to 'support/dktools/dk4sock16.ctr')
-rw-r--r-- | support/dktools/dk4sock16.ctr | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/support/dktools/dk4sock16.ctr b/support/dktools/dk4sock16.ctr new file mode 100644 index 0000000000..ebac56871b --- /dev/null +++ b/support/dktools/dk4sock16.ctr @@ -0,0 +1,274 @@ +%% options + +copyright owner = Dirk Krause +copyright year = 2015-xxxx +license = bsd + + +%% module + +#include "dk4sock.h" + +#include <stdio.h> + +#if !DK4_ON_WINDOWS +#if DK4_HAVE_FCNTL_H +#ifndef FCNTL_H_INCLUDED +#include <fcntl.h> +#define FCNTL_H_INCLUDED 1 +#endif +#endif +#endif + +#if DK4_HAVE_ERRNO_H +#ifndef ERRNO_H_INCLUDED +#include <errno.h> +#define ERRNO_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_UNISTD_H +#ifndef UNISTD_H_INCLUDED +#include <unistd.h> +#define UNISTD_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_IO_H +#ifndef IO_H_INCLUDED +#include <io.h> +#define IO_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_STRING_H +#ifndef STRING_H_INCLUDED +#include <string.h> +#define STRING_H_INCLUDED 1 +#endif +#endif + +$!trace-include + + + +static +dk4_socket_t +dk4socket_tcp_client_cleanup_socket( + dk4_socket_t sock, + int level, + struct sockaddr *pAddr, + size_t szAddr +) +{ +#if 0 + /* Setting SO_REUSEADDR or SO_REUSEPORT must follow socket() + immediately. + */ + if ((0 < level) || ((NULL != pAddr) && (0 < szAddr))) { + (void)dk4socket_option_set_reuse(sock, 1, NULL); + } +#endif + +#if DK4_ON_WINDOWS + closesocket(sock); +#else + close(sock); +#endif + return (INVALID_SOCKET); +} + + + +static +dk4_socket_t +dk4socket_tcp_client_connect_attempt( + dk4_socket_t back, + struct sockaddr *pAddr, + size_t szAddr, + struct sockaddr *pLoAddr, + size_t szLoAddr, + long secs, + long usecs, + dk4_er_t *erp +) +{ + fd_set wfds; + struct timeval to; +#if (!DK4_ON_WINDOWS) && (DK4_HAVE_SETSOCKOPT) \ + && defined(SOL_SOCKET) && defined(SO_ERROR) +#if DK4_HAVE_SOCKLEN_T + socklen_t slo; +#else + int slo; +#endif + int err; +#endif + int res; + $? "+ dk4socket_tcp_client_connect_attempt" + $? ". remote = PTR=%d %lu", TR_IPTR(pAddr), (unsigned long)szAddr + res = dk4socket_connect(back, pAddr, szAddr, erp); + switch (res) { + case DK4_SOCKET_RESULT_SUCCESS : { $? ". connected" + /* do nothing */ + } break; + case DK4_SOCKET_RESULT_IN_PROGRESS : { $? ". in progress" + FD_ZERO(&wfds); + FD_SET(back, &wfds); + to.tv_sec = secs; + to.tv_usec = usecs; + dk4socket_error_reset(); + res = select((((int)back) + 1), NULL, &wfds, NULL, &to); + if (0 < res) { $? ". select" + if (FD_ISSET(back, &wfds)) { $? ". in write set" +#if (!DK4_ON_WINDOWS) && (DK4_HAVE_SETSOCKOPT) \ + && defined(SOL_SOCKET) && defined(SO_ERROR) + err = 0; + slo = sizeof(err); + dk4socket_error_reset(); + res = getsockopt(back, SOL_SOCKET, SO_ERROR, &err, &slo); + if (0 == res) { $? ". getsockopt ok" + if (0 != dk4socket_non_null_getsockopt(err, slo)) { + $? "! non-null from getsockopt" + dk4error_set_idetails(erp, DK4_E_SOCKET_CONNECT, err); + back = dk4socket_tcp_client_cleanup_socket( + back, 1, pLoAddr, szLoAddr + ); + } +#if VERSION_BEFORE_20160415 + if (sizeof(int) != slo) { + if (0 != err) { $? "! error from getsockopt" + dk4error_set_idetails(erp, DK4_E_SOCKET_CONNECT, err); + back = dk4socket_tcp_client_cleanup_socket( + back, 1, pLoAddr, szLoAddr + ); + } + } else { $? "! getsockopt (size)" + dk4socket_error_report(erp, DK4_E_SOCKET_GETSOCKOPT); + back = dk4socket_tcp_client_cleanup_socket( + back, 1, pLoAddr, szLoAddr + ); + } +#endif + } else { $? "! getsockopt" + dk4socket_error_report(erp, DK4_E_SOCKET_GETSOCKOPT); + back = dk4socket_tcp_client_cleanup_socket(back,1,pLoAddr,szLoAddr); + } +#endif + } else { $? "! timeout (not in list)" + dk4error_set_simple_error_code(erp, DK4_E_SOCKET_TIMEOUT); + back = dk4socket_tcp_client_cleanup_socket(back,0,pLoAddr,szLoAddr); + } + } else { + if (0 > res) { $? "! select" + dk4socket_error_report(erp, DK4_E_SOCKET_SELECT); + } else { $? "! timeout (from select)" + dk4error_set_simple_error_code(erp, DK4_E_SOCKET_TIMEOUT); + } + back = dk4socket_tcp_client_cleanup_socket(back,0,pLoAddr,szLoAddr); + } + } break; + default : { $? "! failed" + back = dk4socket_tcp_client_cleanup_socket(back, 0, pLoAddr, szLoAddr); + } break; + } + $? "- dk4socket_tcp_client_connect_attempt %d", (int)back + return back; +} + + + +dk4_socket_t +dk4socket_tcp_client_for_addr( + int protfam, + struct sockaddr *pRemoteAddr, + size_t szRemoteAddr, + struct sockaddr *pLocalAddr, + size_t szLocalAddr, + long seconds, + long microSeconds, + dk4_er_t *erp +) +{ + dk4_socket_t back = INVALID_SOCKET; + int res; +#if DK4_HAVE_SETSOCKOPT && (defined(SO_REUSEPORT) || defined(SO_REUSEADDR)) + int opt = 0; +#endif + $? "+ dk4socket_tcp_client_for_addr" + if ((NULL != pRemoteAddr) && (0 < szRemoteAddr)) { $? ". args ok" + $? ". remote = PTR=%d %lu",TR_IPTR(pRemoteAddr),(unsigned long)szRemoteAddr + back = dk4socket_open(protfam, SOCK_STREAM, 0, erp); + if (INVALID_SOCKET != back) { $? ". socket" + if ((NULL != pLocalAddr) && (0 < szLocalAddr)) { $? ". must bind" +#if DK4_HAVE_SETSOCKOPT && defined(SO_REUSEPORT) + $? ". SO_REUSEPORT" + dk4socket_set_one_bytes(&opt, sizeof(opt)); + res = setsockopt( + back, SOL_SOCKET, + SO_REUSEPORT, (void *)(&opt), sizeof(opt) + ); + if (0 != res) { $? "! failed to reuse port number" + } +#else +#if DK4_HAVE_SETSOCKOPT && defined(SO_REUSEADDR) + $? ". SO_REUSEADDR" + dk4socket_set_one_bytes(&opt, sizeof(opt)); + res = setsockopt( + back, SOL_SOCKET, + SO_REUSEADDR, (void *)(&opt), sizeof(opt) + ); + if (0 != res) { $? "! failed to reuse address" + } +#else + $? ". neither SO_REUSEPORT nor SO_REUSEADDR" +#endif +#endif + res = dk4socket_bind(back, pLocalAddr, szLocalAddr, erp); + if (DK4_SOCKET_RESULT_FAILED == res) { $? "! bind" + back = dk4socket_tcp_client_cleanup_socket( + back, 0, pLocalAddr, szLocalAddr + ); + } + } + if (INVALID_SOCKET != back) { + if ((0L != seconds) || (0L != microSeconds)) { $? ". use timeout" + res = dk4socket_option_set_nonblock(back, 1, erp); + if (DK4_SOCKET_RESULT_SUCCESS == res) { $? ". non-blocking" + back = dk4socket_tcp_client_connect_attempt( + back, pRemoteAddr, szRemoteAddr, pLocalAddr, szLocalAddr, + seconds, microSeconds, erp + ); + if (INVALID_SOCKET != back) { + res = dk4socket_option_set_nonblock(back, 0, erp); + if (DK4_SOCKET_RESULT_SUCCESS != res) { $? "! back blocking" + back = dk4socket_tcp_client_cleanup_socket( + back, 1, pLocalAddr, szLocalAddr + ); + } + } + } else { $? "! non-blocking" + back = dk4socket_tcp_client_cleanup_socket( + back, 0, pLocalAddr, szLocalAddr + ); + } + } else { $? ". no timeout" + back = dk4socket_tcp_client_connect_attempt( + back, pRemoteAddr, szRemoteAddr, pLocalAddr, szLocalAddr, + 0L, 0L, erp + ); + } + } + } else { $? "! socket" + $? "! errno=%d", errno + } + } else { $? "! args" + dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); + } + $? "- dk4socket_tcp_client_for_addr %d", (int)back + return back; +} + + + + |