/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. 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 Dirk Krause 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 dktcpip.c TCP/IP client side implementation. */ #include "dk.h" #include "dktypes.h" #include "dkmem.h" #include "dksf.h" #include "dkenc.h" #include "dkma.h" #include "dkerror.h" #include /** Inside the dktcpip module. */ #define DK_TCPIP_C 1 #include "dktcpip.h" #if DK_HAVE_STRING_H #include #endif #if DK_HAVE_CTYPE_H #include #endif #if DK_HAVE_ARPA_INET_H #include #endif #if DK_HAVE_NETDB_H #include #endif #if DK_HAVE_ERRNO_H #include #endif #if DK_HAVE_FCNTL_H #include #endif #if DK_HAVE_UNISTD_H #include #endif #if DK_HAVE_STDLIB_H #include #endif $(trace-include) /** Translate system error code to DK_ERR_xxx error code using a table. @param i System error code. @param a Translation array. @param n Number of entries in translation array. @return Translated error code or original error code. */ static int translate(int i, int *a, size_t n) { int back; size_t j; back = i; if(a) { for(j = 0; j < n; j++) { if(a[2*j] == i) { back = a[2*j+1]; } } } return back; } /** Translate system error code to DK_ERR_xxx error code. */ #define TRANSL(i,a) translate(i,a,(sizeof(a)/(2*sizeof(int)))); #if DK_HAVE_SYS_SOCKET_H /** Translation from WSAxxx errors to DK_ERR_xxx errors for select(). */ static int select_error_translation[] = { #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EINTR EINTR , DK_ERR_INTERRUPTED , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_FILEHANDLE , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for gethostbyname(). */ static int gethostbyname_error_translation[] = { #ifdef HOST_NOT_FOUND HOST_NOT_FOUND , DK_ERR_NO_SUCH_HOST , #endif #ifdef TRY_AGAIN TRY_AGAIN , DK_ERR_TRY_AGAIN , #endif #ifdef NO_RECOVERY NO_RECOVERY , DK_ERR_NO_RECOVERY , #endif #ifdef NO_DATA NO_DATA , DK_ERR_NO_DNS_RESPONSE , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for socket(). */ static int socket_error_translation[] = { #ifdef EACCES EACCES , DK_ERR_ACCESS , #endif #ifdef EAFNOSUPPORT EAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef EMFILE EMFILE , DK_ERR_RESOURCES , #endif #ifdef ENFILE ENFILE , DK_ERR_RESOURCES , #endif #ifdef EPROTONOSUPPORT EPROTONOSUPPORT , DK_ERR_PROTO_NOT_SUPPORTED , #endif #ifdef EPROTOTYPE EPROTOTYPE , DK_ERR_PROTO_NOT_SUPPORTED , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOMEM ENOMEM , DK_ERR_NOMEM , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for bind(). */ static int bind_error_translation[] = { #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef ENOTSOCK ENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EADDRNOTAVAIL EADDRNOTAVAIL , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif #ifdef EADDRINUSE EADDRINUSE , DK_ERR_ADDRESS_IN_USE , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EACCES EACCES , DK_ERR_ACCESS , #endif #ifdef EAFNOSUPPORT EAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef EOPNOTSUPP EOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef EISCONN EISCONN , DK_ERR_ALREADY_CONNECTED , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for connect(). */ static int connect_error_translation[] = { #ifdef EADDRNOTAVAIL EADDRNOTAVAIL , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif #ifdef EAFNOSUPPORT EAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef EALREADY EALREADY , DK_ERR_CONNECT_IN_PROGRESS , #endif #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef ECONNREFUSED ECONNREFUSED , DK_ERR_CONNECTION_REFUSED_BY_PEER , #endif #ifdef EINPROGRESS EINPROGRESS , DK_ERR_TRY_AGAIN , #endif #ifdef EINTR EINTR , DK_ERR_INTERRUPTED , #endif #ifdef EISCONN EISCONN , DK_ERR_ALREADY_CONNECTED , #endif #ifdef ENETUNREACH ENETUNREACH , DK_ERR_NET_UNREACHABLE , #endif #ifdef ENOTSOCK ENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EPROTOTYPE EPROTOTYPE , DK_ERR_PROTO_NOT_SUPPORTED , #endif #ifdef ETIMEDOUT ETIMEDOUT , DK_ERR_TIMED_OUT , #endif #ifdef EADDRINUSE EADDRINUSE , DK_ERR_ADDRESS_IN_USE , #endif #ifdef ECONNRESET ECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef EHOSTUNREACH EHOSTUNREACH , DK_ERR_HOST_UNREACHABLE , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef ENETDOWN ENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif #ifdef EOPNOTSUPP EOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for recvfrom(). */ static int recvfrom_error_translation[] = { #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef ECONNRESET ECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef EINTR EINTR , DK_ERR_INTERRUPTED , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef ENOTCONN ENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef ENOTSOCK ENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EOPNOTSUPP EOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef ETIMEDOUT ETIMEDOUT , DK_ERR_TIMED_OUT , #endif #ifdef EAGAIN EAGAIN , DK_ERR_TRY_AGAIN , #endif #ifdef EIO EIO , DK_ERR_IO , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOMEM ENOMEM , DK_ERR_NOMEM , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for recv(). */ static int recv_error_translation[] = { #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef ECONNRESET ECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef EINTR EINTR , DK_ERR_INTERRUPTED , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef ENOTCONN ENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef ENOTSOCK ENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EOPNOTSUPP EOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef ETIMEDOUT ETIMEDOUT , DK_ERR_TIMED_OUT , #endif #ifdef EAGAIN EAGAIN , DK_ERR_TRY_AGAIN , #endif #ifdef EIO EIO , DK_ERR_IO , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOMEM ENOMEM , DK_ERR_NOMEM , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for sendto(). */ static int sendto_error_translation[] = { #ifdef EAFNOSUPPORT EAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef ECONNRESET ECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef EINTR EINTR , DK_ERR_INTERRUPTED , #endif #ifdef EMSGSIZE EMSGSIZE , DK_ERR_MSG_SIZE , #endif #ifdef ENOTCONN ENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef ENOTSOCK ENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EOPNOTSUPP EOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef EPIPE EPIPE , DK_ERR_PIPE , #endif #ifdef EAGAIN EAGAIN , DK_ERR_TRY_AGAIN , #endif #ifdef EDESTADDRREQ EDESTADDRREQ , DK_ERR_INVALID_ARGS , #endif #ifdef EHOSTUNREACH EHOSTUNREACH , DK_ERR_HOST_UNREACHABLE , #endif #ifdef EINVAL EINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef EIO EIO , DK_ERR_IO , #endif #ifdef EISCONN EISCONN , DK_ERR_ALREADY_CONNECTED , #endif #ifdef ENETDOWN ENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef ENETUNREACH ENETUNREACH , DK_ERR_NET_UNREACHABLE , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOMEM ENOMEM , DK_ERR_NOMEM , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for send(). */ static int send_error_translation[] = { #ifdef EBADF EBADF , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef ECONNRESET ECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef EDESTADDRREQ EDESTADDRREQ , DK_ERR_INVALID_ARGS , #endif #ifdef EINTR EINTR , DK_ERR_INTERRUPTED , #endif #ifdef EMSGSIZE EMSGSIZE , DK_ERR_MSG_SIZE , #endif #ifdef ENOTCONN ENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef ENOTSOCK ENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef EOPNOTSUPP EOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef EPIPE EPIPE , DK_ERR_PIPE , #endif #ifdef EAGAIN EAGAIN , DK_ERR_TRY_AGAIN , #endif #ifdef ENETDOWN ENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef ENETUNREACH ENETUNREACH , DK_ERR_NET_UNREACHABLE , #endif #ifdef ENOBUFS ENOBUFS , DK_ERR_RESOURCES , #endif #ifdef ENOSR ENOSR , DK_ERR_RESOURCES , #endif #ifdef EIO EIO , DK_ERR_IO , #endif 0, 0 } ; #else #if DK_HAVE_WINSOCK2_H /** Translation from WSAxxx errors to DK_ERR_xxx errors for socket(). */ static int socket_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEAFNOSUPPORT WSAEAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEMFILE WSAEMFILE , DK_ERR_RESOURCES , #endif #ifdef WSAENOBUFS WSAENOBUFS , DK_ERR_RESOURCES , #endif #ifdef WSAEPROTONOSUPPORT WSAEPROTONOSUPPORT , DK_ERR_PROTO_NOT_SUPPORTED , #endif #ifdef WSAEPROTOTYPE WSAEPROTOTYPE , DK_ERR_PROTO_NOT_SUPPORTED , #endif #ifdef WSAESOCKETNOSUPPORT WSAESOCKETNOSUPPORT , DK_ERR_PROTO_NOT_SUPPORTED , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for bind(). */ static int bind_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEADDRINUSE WSAEADDRINUSE , DK_ERR_ADDRESS_IN_USE , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENOBUFS WSAENOBUFS , DK_ERR_RESOURCES , #endif #ifdef WSAENOTSOCK WSAENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for connect(). */ static int connect_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEADDRINUSE WSAEADDRINUSE , DK_ERR_ADDRESS_IN_USE , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEALREADY WSAEALREADY , DK_ERR_BUSY , #endif #ifdef WSAEADDRNOTAVAIL WSAEADDRNOTAVAIL , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif #ifdef WSAEAFNOSUPPORT WSAEAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef WSAECONNREFUSED WSAECONNREFUSED , DK_ERR_CONNECTION_REFUSED_BY_PEER , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEISCONN WSAEISCONN , DK_ERR_ALREADY_CONNECTED , #endif #ifdef WSAENETUNREACH WSAENETUNREACH , DK_ERR_NET_UNREACHABLE , #endif #ifdef WSAENOBUFS WSAENOBUFS , DK_ERR_RESOURCES , #endif #ifdef WSAENOTSOCK WSAENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef WSAETIMEDOUT WSAETIMEDOUT , DK_ERR_TIMED_OUT , #endif #ifdef WSAEWOULDBLOCK WSAEWOULDBLOCK , DK_ERR_TRY_AGAIN , #endif #ifdef WSAEACCESS WSAEACCESS , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for recvfrom(). */ static int recvfrom_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENETRESET WSAENETRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAENOTCONN WSAENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef WSAENOTSOCK WSAENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef WSAEOPNOTSUPP WSAEOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef WSAESHUTDOWN WSAESHUTDOWN , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEWOULDBLOCK WSAEWOULDBLOCK , DK_ERR_TRY_AGAIN , #endif #ifdef WSAEMSGSIZE WSAEMSGSIZE , DK_ERR_MSG_SIZE , #endif #ifdef WSAECONNABORTED WSAECONNABORTED , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAETIMEDOUT WSAETIMEDOUT , DK_ERR_TIMED_OUT , #endif #ifdef WSAECONNRESET WSAECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for recv(). */ static int recv_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENOTCONN WSAENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAENETRESET WSAENETRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAENOTSOCK WSAENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef WSAEOPNOTSUPP WSAEOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef WSAESHUTDOWN WSAESHUTDOWN , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEWOULDBLOCK WSAEWOULDBLOCK , DK_ERR_TRY_AGAIN , #endif #ifdef WSAEMSGSIZE WSAEMSGSIZE , DK_ERR_MSG_SIZE , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAECONNABORTED WSAECONNABORTED , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAETIMEDOUT WSAETIMEDOUT , DK_ERR_TIMED_OUT , #endif #ifdef WSAECONNRESET WSAECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for sendto(). */ static int sendto_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEACCESS WSAEACCESS , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENETRESET WSAENETRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAENOBUFS WSAENOBUFS , DK_ERR_RESOURCES , #endif #ifdef WSAENOTCONN WSAENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef WSAEOPNOTSUPP WSAEOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef WSAESHUTDOWN WSAESHUTDOWN , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEWOULDBLOCK WSAEWOULDBLOCK , DK_ERR_TRY_AGAIN , #endif #ifdef WSAEMSGSIZE WSAEMSGSIZE , DK_ERR_MSG_SIZE , #endif #ifdef WSAEHOSTUNREACH WSAEHOSTUNREACH , DK_ERR_HOST_UNREACHABLE , #endif #ifdef WSAECONNABORTED WSAECONNABORTED , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAECONNRESET WSAECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAEADDRNOTAVAIL WSAEADDRNOTAVAIL , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif #ifdef WSAEAFNOSUPPORT WSAEAFNOSUPPORT , DK_ERR_AF_NO_SUPPORT , #endif #ifdef WSAEDESTADDRREQ WSAEDESTADDRREQ , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENETUNREACH WSAENETUNREACH , DK_ERR_NET_UNREACHABLE , #endif #ifdef WSAETIMEDOUT WSAETIMEDOUT , DK_ERR_TIMED_OUT , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for send(). */ static int send_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEACCESS WSAEACCESS , DK_ERR_ADDRESS_NOT_AVAILABLE , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENETRESET WSAENETRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAENOBUFS WSAENOBUFS , DK_ERR_RESOURCES , #endif #ifdef WSAENOTCONN WSAENOTCONN , DK_ERR_NOT_CONNECTED , #endif #ifdef WSAENOTSOCK WSAENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif #ifdef WSAEOPNOTSUPP WSAEOPNOTSUPP , DK_ERR_INVALID_ARGS , #endif #ifdef WSAESHUTDOWN WSAESHUTDOWN , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEWOULDBLOCK WSAEWOULDBLOCK , DK_ERR_TRY_AGAIN , #endif #ifdef WSAEMSGSIZE WSAEMSGSIZE , DK_ERR_MSG_SIZE , #endif #ifdef WSAEHOSTUNREACH WSAEHOSTUNREACH , DK_ERR_HOST_UNREACHABLE , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAECONNABORTED WSAECONNABORTED , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAECONNRESET WSAECONNRESET , DK_ERR_CONNECTION_CLOSED_BY_PEER , #endif #ifdef WSAETIMEDOUT WSAETIMEDOUT , DK_ERR_TIMED_OUT , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for gethostbyname(). */ static int gethostbyname_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAHOST_NOT_FOUND WSAHOST_NOT_FOUND , DK_ERR_NO_SUCH_HOST , #endif #ifdef WSATRY_AGAIN WSATRY_AGAIN , DK_ERR_TRY_AGAIN , #endif #ifdef WSANO_RECOVERY WSANO_RECOVERY , DK_ERR_NO_RECOVERY , #endif #ifdef WSANO_DATA WSANO_DATA , DK_ERR_NO_DNS_RESPONSE , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif 0, 0 } ; /** Translation from WSAxxx errors to DK_ERR_xxx errors for select(). */ static int select_error_translation[] = { #ifdef WSANOTINITIALIZED WSANOTINITIALIZED , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEFAULT WSAEFAULT , DK_ERR_INVALID_ARGS , #endif #ifdef WSAENETDOWN WSAENETDOWN , DK_ERR_NET_INTERFACE_DOWN , #endif #ifdef WSAEINVAL WSAEINVAL , DK_ERR_INVALID_ARGS , #endif #ifdef WSAEINTR WSAEINTR , DK_ERR_INTERRUPTED , #endif #ifdef WSAEINPROGRESS WSAEINPROGRESS , DK_ERR_BUSY , #endif #ifdef WSAENOTSOCK WSAENOTSOCK , DK_ERR_INVALID_FILEHANDLE , #endif 0, 0 } ; #endif #endif /** Retrieve 1st part of IP address. */ #define IP1(addr) ((dkenc_ntohl(addr) >> 24) & 0x000000FFUL) /** Retrieve 2nd part of IP address. */ #define IP2(addr) ((dkenc_ntohl(addr) >> 16) & 0x000000FFUL) /** Retrieve 3rd part of IP address. */ #define IP3(addr) ((dkenc_ntohl(addr) >> 8) & 0x000000FFUL) /** Retrieve 4th part of IP address. */ #define IP4(addr) ((dkenc_ntohl(addr)) & 0x000000FFUL) /** Abbreviation for use with sizeof operator. */ typedef struct sockaddr_in SOIN; /** IP address type: Unknown. */ #define DKIPADDR_TYPE_UNKNOWN 0 /** IP address type: IPv4. */ #define DKIPADDR_TYPE_IP4 1 /** IP address type: IPv6. */ #define DKIPADDR_TYPE_IP6 2 /** State: Endpoint not yet usable. */ #define DKIP_STATE_NEW 0 /** State: Endpoint ready to use. */ #define DKIP_STATE_OPENED 1 /** State: Socket no longer in use. */ #define DKIP_STATE_OVER 2 /** @defgroup tcpipflags TCP/IP flags.*/ /**@{*/ /** Connectionless socket. */ #define DKIP_FLAG_CONLESS 1 /** Socket closed for read operations. */ #define DKIP_FLAG_RDCLOSED 2 /** Socket closed for write operations. */ #define DKIP_FLAG_WRCLOSED 4 /** Use a timeout. */ #define DKIP_FLAG_TIMEOUT 8 /** Non-blocking mode. */ #define DKIP_FLAG_NONBLOCK 16 /** Reuse address. */ #define DKIP_FLAG_REUSE 32 /** Send/receive broadcast messages. */ #define DKIP_FLAG_BROADCAST 64 /** Keep alive. */ #define DKIP_FLAG_KEEPALIVE 128 /**@}*/ #if DK_HAVE_WINSOCK2_H /** Number of times we started Windows sockets. */ static unsigned long number_of_starts = 0UL; /** Flag: Windows socket started successfully. */ static int started_successfully = 0; #endif /** Initialize IP address structure. @param a Address to initialize. */ static void dktcpipaddr_init DK_P1(dk_ip_addr_t *,a) { $? "+ dktcpipaddr_init %s", TR_PTR(a) if(a) { DK_MEMRES(a,sizeof(dk_ip_addr_t)); a->what = 0; (a->ip4).portmin = 0; (a->ip4).portmax = 0; (a->ip4).sin.sin_family = AF_INET; #ifdef INADDR_ANY (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(INADDR_ANY); #else (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(0UL); #endif (a->ip4).sin.sin_port = htons(0); } $? "- dktcpipaddr_init" } /** Set/reset reuse-address flag. @param t Socket to modify. @param fl New reuse-address flag value. @return 1 on success, 0 on error. */ static int set_reuse DK_P2(int, t, int, fl) { int back = 0; #if DK_HAVE_SETSOCKOPT #ifdef SO_REUSEADDR int opt, status; $? "+ set_reuse %d %d", t, fl if(t >= 0) { opt = (fl ? 1 : 0); status=setsockopt(t,SOL_SOCKET,SO_REUSEADDR,((char *)(&opt)),sizeof(opt)); $? ". set_reuse setsockopt() = %d", status back = ((status == 0) ? 1 : 0); } $? "- set_reuse %d", back #else $? "! SO_REUSEADDR undefined" #endif #else $? "! DK_HAVE_SETSOCKOPT undefined" #endif return back; } /** Set/reset broadcast flag. @param t Socket to modify. @param fl New broadcast flag value. @return 1 on success, 0 on error. */ static int set_broadcast DK_P2(int, t, int, fl) { int back = 0; #if DK_HAVE_SETSOCKOPT #ifdef SO_BROADCAST int opt, status; $? "+ set_broadcast %d %d", t, fl if(t >= 0) { opt = (fl ? 1 : 0); status=setsockopt(t,SOL_SOCKET,SO_BROADCAST,((char *)(&opt)),sizeof(opt)); $? ". set_broadcast setsockopt() = %d", status back = ((status == 0) ? 1 : 0); } $? "- set_broadcast %d", back #else $? "! SO_BROADCAST undefined" #endif #else $? "! DK_HAVE_SETSOCKOPT undefined" #endif return back; } /** Set/reset keep-alive flag. @param t Socket to modify. @param fl New keep-alive flag value. @return 1 on success, 0 on error. */ static int set_keepalive DK_P2(int, t, int, fl) { int back = 0; #if DK_HAVE_SETSOCKOPT #ifdef SO_KEEPALIVE int opt, status; $? "+ set_keepalive %d %d", t, fl if(t >= 0) { opt = (fl ? 1 : 0); status=setsockopt(t,SOL_SOCKET,SO_KEEPALIVE,((char *)(&opt)),sizeof(opt)); $? ". set_keepalive setsockopt() = %d", status back = ((status == 0) ? 1 : 0); } $? "- set_keepalive %d", back #else $? "! SO_KEEPALIVE undefined" #endif #else $? "! DK_HAVE_SETSOCKOPT undefined" #endif return back; } int dktcpip_set_reuse DK_P2(dk_tcpip_t *, t, int, fl) { int back = 0; $? "+ dktcpip_set_reuse %s %d", TR_PTR(t), fl if(t) { switch(t->state) { case DKIP_STATE_NEW : { if(fl) { t->flags |= DKIP_FLAG_REUSE; } else { t->flags &= (~(DKIP_FLAG_REUSE)); } $? ". marking socket for later setsockopt" back = 1; } break; case DKIP_STATE_OPENED : { if(fl) { t->flags |= DKIP_FLAG_REUSE; } else { t->flags &= (~(DKIP_FLAG_REUSE)); } $? ". working on opened socket" back = set_reuse(t->s, fl); } break; } } $? "- dktcpip_set_reuse %d", back return back; } int dktcpip_set_broadcast DK_P2(dk_tcpip_t *, t, int, fl) { int back = 0; $? "+ dktcpip_set_broadcast %s %d", TR_PTR(t), fl if(t) { switch(t->state) { case DKIP_STATE_NEW : { if(fl) { t->flags |= DKIP_FLAG_BROADCAST; } else { t->flags &= (~(DKIP_FLAG_BROADCAST)); } $? ". marking socket for later setsockopt" back = 1; } break; case DKIP_STATE_OPENED : { if(fl) { t->flags |= DKIP_FLAG_BROADCAST; } else { t->flags &= (~(DKIP_FLAG_BROADCAST)); } $? ". working on opened socket" if((t->flags) & DKIP_FLAG_CONLESS) { back = set_broadcast(t->s, fl); } else { back = 1; } } break; } } $? "- dktcpip_set_broadcast %d", back return back; } int dktcpip_set_keepalive DK_P2(dk_tcpip_t *, t, int, fl) { int back = 0; $? "+ dktcpip_set_keepalive %s %d", TR_PTR(t), fl if(t) { switch(t->state) { case DKIP_STATE_NEW : { if(fl) { t->flags |= DKIP_FLAG_KEEPALIVE; } else { t->flags &= (~(DKIP_FLAG_KEEPALIVE)); } $? ". marking socket for later setsockopt" back = 1; } break; case DKIP_STATE_OPENED : { if(fl) { t->flags |= DKIP_FLAG_KEEPALIVE; } else { t->flags &= (~(DKIP_FLAG_KEEPALIVE)); } $? ". working on opened socket" back = set_keepalive(t->s, fl); } break; } } $? "- dktcpip_set_keepalive %d", back return back; } /** Obtain IP address from dotted decimal notation. @param hn IP address in dotted decimal notation. @return IP in host byte order. */ static unsigned long dotted_string_to_ip DK_P1(char *, hn) { unsigned long back = 0UL; unsigned long u1, u2, u3, u4, u; int ende, state; char *ptr; $? "+ dotted_string_to_ip %s", TR_STR(hn) if(hn) { state = 0; u = u1 = u2 = u3 = u4 = 0UL; ptr = hn; ende = 0; while(!ende) { if(*ptr) { if(isdigit(*ptr)) { u = 0UL; switch(*ptr) { case '0': u = 0UL; break; case '1': u = 1UL; break; case '2': u = 2UL; break; case '3': u = 3UL; break; case '4': u = 4UL; break; case '5': u = 5UL; break; case '6': u = 6UL; break; case '7': u = 7UL; break; case '8': u = 8UL; break; case '9': u = 9UL; break; } switch(state) { case 0: u1 = 10UL * u1 + u; break; case 1: u2 = 10UL * u2 + u; break; case 2: u3 = 10UL * u3 + u; break; case 3: u4 = 10UL * u4 + u; break; } } else { if(*ptr == '.') { state++; if(state >= 4) { ende = 1; } } } ptr++; } else { ende = 1; } } } u1 = u1 << 24; u1 = u1 & 0xFF000000UL; u2 = u2 << 16; u2 = u2 & 0x00FF0000UL; u3 = u3 << 8; u3 = u3 & 0x0000FF00UL; u4 = u4 & 0x000000FFUL; back = u1 | u2 | u3 | u4; $? "- dotted_string_to_ip %lu.%lu.%lu.%lu", u1, u2, u3, u4 return back; } #ifdef DNS_LOOKUP_FIRST int dktcpipaddr_set_ip_byname DK_P3(dk_ip_addr_t *, a, char *, hn, dk_tcpip_t *, p) { int back = 0; #if DK_HAVE_GETHOSTBYNAME struct hostent *hp; unsigned long *lp; #endif $? "+ dktcpipaddr_set_ip_byname %s", TR_STR(hn) if(a && hn) { #if DK_HAVE_GETHOSTBYNAME hp = gethostbyname(hn); if(hp) { $? ". hostname found" if(hp->h_addr_list) { $? ". list ok" if(hp->h_length) { $? ". list length ok" lp = (unsigned long *)(*(hp->h_addr_list)); if(lp) { $? ". lp ok" back = 1; a->what = DKIPADDR_TYPE_IP4; (a->ip4).sin.sin_addr.s_addr = *lp; } else { if(p) p->error_code = DK_ERR_UNKNOWN_ERROR; } } else { if(p) p->error_code = DK_ERR_UNKNOWN_ERROR; } } else { if(p) p->error_code = DK_ERR_UNKNOWN_ERROR; } } else { if(p) p->error_code = TRANSL(h_errno,gethostbyname_error_translation); (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(dotted_string_to_ip(hn)); if((a->ip4).sin.sin_addr.s_addr) { back = 1; a->what = DKIPADDR_TYPE_IP4; } } #else if(p) p->error_code = DK_ERR_NO_GETHOSTBYNAME; #endif } else { if(p) p->error_code = DK_ERR_INVALID_ARGS; } $? "- dktcpipaddr_set_ip_byname %lu.%lu.%lu.%lu", IP1((a->ip4).sin.sin_addr.s_addr), IP2((a->ip4).sin.sin_addr.s_addr), IP3((a->ip4).sin.sin_addr.s_addr), IP4((a->ip4).sin.sin_addr.s_addr) return back; } #else int dktcpipaddr_set_ip_byname DK_P3(dk_ip_addr_t *, a, char *, hn, dk_tcpip_t *, p) { int back = 0; #if DK_HAVE_GETHOSTBYNAME struct hostent *hp; unsigned long *lp; #endif $? "+ dktcpipaddr_set_ip_byname %s", TR_STR(hn) if(a && hn) { (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(dotted_string_to_ip(hn)); if((a->ip4).sin.sin_addr.s_addr) { back = 1; a->what = DKIPADDR_TYPE_IP4; } else { /* if((a->ip4).sin.sin_addr.s_addr) */ #if DK_HAVE_GETHOSTBYNAME hp = gethostbyname(hn); if(hp) { $? ". hostname found" if(hp->h_addr_list) { $? ". list ok" if(hp->h_length) { $? ". list length ok" lp = (unsigned long *)(*(hp->h_addr_list)); if(lp) { $? ". lp ok" back = 1; a->what = DKIPADDR_TYPE_IP4; (a->ip4).sin.sin_addr.s_addr = *lp; } else { if(p) p->error_code = DK_ERR_UNKNOWN_ERROR; } } else { if(p) p->error_code = DK_ERR_UNKNOWN_ERROR; } } else { if(p) p->error_code = DK_ERR_UNKNOWN_ERROR; } } else { if(p) p->error_code = TRANSL(h_errno,gethostbyname_error_translation); } #else if(p) p->error_code = DK_ERR_NO_GETHOSTBYNAME; #endif } /* if((a->ip4).sin.sin_addr.s_addr) */ } else { /* if(a && hn) */ if(p) p->error_code = DK_ERR_INVALID_ARGS; } /* if(a && hn) */ $? ". %lu.%lu.%lu.%lu", IP1((a->ip4).sin.sin_addr.s_addr), IP2((a->ip4).sin.sin_addr.s_addr), IP3((a->ip4).sin.sin_addr.s_addr), IP4((a->ip4).sin.sin_addr.s_addr) $? "- dktcpipaddr_set_ip_byname %d", back return back; } #endif /* DNS_LOOKUP_FIRST */ int dktcpipaddr_set_ip_loopback DK_P1(dk_ip_addr_t *, a) { int back = 0; $? "+ dktcpipaddr_set_ip_loopback %s", TR_PTR(a) if(a) { back = 1; a->what = DKIPADDR_TYPE_IP4; #ifdef INADDR_LOOPBACK (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(INADDR_LOOPBACK); #else (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(0x7F000001UL); #endif } $? "- dktcpipaddr_set_ip_loopback %d", back return back; } int dktcpipaddr_set_ip_local DK_P2(dk_ip_addr_t *, a, dk_tcpip_t *, p) { int back = 0; char *hostname; $? "+ dktcpipaddr_set_ip_local %s", TR_PTR(a) hostname = dk_new(char,1024); if(hostname) { if(a) { if(dksf_get_hostname(hostname, 1024)) { back = dktcpipaddr_set_ip_byname(a, hostname, p); } else { if(p) p->error_code = DK_ERR_GETHOSTNAME_FAILED; } } else { if(p) p->error_code = DK_ERR_INVALID_ARGS; } dk_delete(hostname); hostname = NULL; } $? "- dktcpipaddr_set_ip_local %d", back return back; } int dktcpipaddr_set_ip_any DK_P1(dk_ip_addr_t *, a) { int back = 0; $? "+ dktcpipaddr_set_ip_any %s", TR_PTR(a) if(a) { back = 1; a->what = DKIPADDR_TYPE_IP4; #ifdef IPADDR_ANY (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(IPADDR_ANY); #else (a->ip4).sin.sin_addr.s_addr = dkenc_htonl(0UL); #endif } $? "- dktcpipaddr_set_ip_any %d", back return back; } void dktcpip_init DK_P1(dk_tcpip_t *,p) { $? "+ dktcpip_init %s", TR_PTR(p) if(p) { p->state = DKIP_STATE_NEW; p->flags = 0; dktcpipaddr_init(&((p->a).l.w)); dktcpipaddr_init(&((p->a).l.f)); dktcpipaddr_init(&((p->a).r.w)); dktcpipaddr_init(&((p->a).r.f)); #if DK_HAVE_WINSOCK2_H p->s = ((SOCKET)(-1)); #else p->s = -1; #endif (p->to).seconds = 0UL; (p->to).usecs = 0L; p->error_code = 0; } $? "- dktcpip_init" } dk_tcpip_t * dktcpip_new DK_P0() { dk_tcpip_t *back = NULL; $? "+ dktcpip_new" back = dk_new(dk_tcpip_t,1); if(back) { dktcpip_init(back); } $? "- dktcpip_new %s", TR_PTR(back) return back; } void dktcpip_delete DK_P1(dk_tcpip_t *, p) { $? "+ dktcpip_delete %s", TR_PTR(p) if(p) { (void)dktcpip_down(p); dk_delete(p); } $? "- dktcpip_delete" } int dktcpip_start DK_P0() { int back = 0; #if DK_HAVE_SYS_SOCKET_H $? "+ dktcpip_start" $? ". BSD sockets" back = 1; #else #if DK_HAVE_WINSOCK2_H WORD version_requested; WSADATA wsa_data; $? "+ dktcpip_start" $? ". Winsock" if(number_of_starts == 0UL) { $? ". trying to load winsock" version_requested = MAKEWORD(2,0); back = WSAStartup(version_requested,&wsa_data); back = (back ? 0 : 1); started_successfully = back; } else { back = started_successfully; } number_of_starts++; #else #endif #endif $? "dktcpip_start %d", back return back; } int dktcpip_set_connectionless DK_P2(dk_tcpip_t *, p, int, flag) { int back = 0; $? "+ dktcpip_set_connectionless %s %d", TR_PTR(p), flag if(p) { switch(p->state) { case DKIP_STATE_NEW: { back = 1; if(flag) { p->flags |= DKIP_FLAG_CONLESS; } else { p->flags &= (~(DKIP_FLAG_CONLESS)); } } break; default : { p->error_code = DK_ERR_NOT_NOW; } break; } } $? "- dktcpip_set_connectionless %d", back return back; } int dktcpip_addr_set_port DK_P3(dk_ip_addr_t *, a, unsigned short, min, unsigned short, max) { int back = 0; $? "+ dktcpip_addr_set_port %s %u %u", TR_PTR(a), min, max if(a) { back = 1; (a->ip4).portmin = min; (a->ip4).portmax = max; } $? "- dktcpip_addr_set_port %d", back return back; } dk_ip_addr_t * dktcpip_get_addr DK_P2(dk_tcpip_t *, p, int, w) { dk_ip_addr_t *back = NULL; $? "+ dktcpip_get_addr %s %d", TR_PTR(p), w if(p) { switch(w) { case DK_IP_ADDR_REMOTE_FOUND : { back = &((p->a).r.f); } break; case DK_IP_ADDR_LOCAL_WISHED : { back = &((p->a).l.w); } break; case DK_IP_ADDR_LOCAL_FOUND : { back = &((p->a).l.f); } break; default : { back = &((p->a).r.w); } break; } } $? "- dktcpip_get_addr %s", TR_PTR(back) return back; } int dktcpip_read DK_P3(dk_tcpip_t *, t, char *, buf, size_t *, lgt) { int back = 0; int xlgt; dk_socklen_t addrlgt; #if DK_HAVE_SELECT fd_set rfds, wfds, efds; struct timeval to; #endif $? "+ dktcpip_read %s %s %s", TR_PTR(t), TR_PTR(buf), TR_PTR(lgt) if(t && buf && lgt) { $? ". length %lu", (unsigned long)(*lgt) switch(t->state) { case DKIP_STATE_OPENED : { #if DK_HAVE_SYS_SOCKET_H if(!((t->flags) & DKIP_FLAG_RDCLOSED)) { if((t->flags) & DKIP_FLAG_CONLESS) { DK_MEMCPY(&((t->a).r.f), &((t->a).r.w), sizeof(dk_ip_addr_t)) ; (t->a).r.f.ip4.sin.sin_port = dkenc_htons((t->a).r.f.ip4.portmin); addrlgt = sizeof(SOIN); xlgt = (int)recvfrom(t->s, buf, *lgt, 0, ((struct sockaddr *)(&((t->a).r.f.ip4.sin))), &addrlgt); if(xlgt >= 0) { *lgt = (size_t)xlgt; back = 1; (t->a).r.f.ip4.portmin = (t->a).r.f.ip4.portmax = dkenc_ntohs((t->a).r.f.ip4.sin.sin_port); } else { $? "! recvfrom failed" t->error_code = TRANSL(errno,recvfrom_error_translation); } } else { back = 1; if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { $? ". not non-blocking" if((t->flags) & DKIP_FLAG_TIMEOUT) { $? ". use timeout" #if DK_HAVE_SELECT $? ". have select" back = 0; to.tv_sec = (long)((t->to).seconds); to.tv_usec = (t->to).usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(t->s, &rfds); FD_SET(t->s, &efds); if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) { $? ". select succeeded" if((FD_ISSET(t->s, &rfds)) || (FD_ISSET(t->s, &efds))) { $? ". stream ready" back = 1; } else { $? "! stream not yet ready" t->error_code = DK_ERR_TIMED_OUT ; } } else { $? "! select failed" t->error_code = TRANSL(errno,select_error_translation); } #endif } } else { $? ". non-blocking" } if(back) { $? ". ok to start read" back = 0; xlgt = (int)recv(t->s, buf, *lgt, 0); $? "%d bytes", xlgt if(xlgt >= 0) { back = 1; *lgt = (size_t)xlgt; if(xlgt == 0) { if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { t->flags |= DKIP_FLAG_RDCLOSED; } } } else { $? "! recv failed" switch(errno) { #ifdef ECONNRESET case ECONNRESET: { close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); } break; #endif #ifdef ENETDOWN case ENETDOWN: { close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); } break; #endif #ifdef ETIMEDOUT case ETIMEDOUT : { close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); } break; #endif } t->error_code = TRANSL(errno,recv_error_translation); } } } } else { t->error_code = DK_ERR_NOT_NOW; } #else #if DK_HAVE_WINSOCK2_H if(started_successfully) { if(!((t->flags) & DKIP_FLAG_RDCLOSED)) { if((t->flags) & DKIP_FLAG_CONLESS) { $? ". connectionless" DK_MEMCPY(&((t->a).r.f), &((t->a).r.w), sizeof(dk_ip_addr_t)) ; (t->a).r.f.ip4.sin.sin_port = dkenc_htons((t->a).r.f.ip4.portmin); addrlgt = sizeof(SOIN); xlgt = (int)recvfrom(t->s, buf, *lgt, 0, ((struct sockaddr *)(&((t->a).r.f.ip4.sin))), &addrlgt); if(xlgt >= 0) { $? ". recvfrom succeeded" *lgt = (size_t)xlgt; back = 1; (t->a).r.f.ip4.portmin = (t->a).r.f.ip4.portmax = dkenc_ntohs((t->a).r.f.ip4.sin.sin_port); } else { $? "! recvfrom failed" t->error_code = WSAGetLastError(); switch(t->error_code) { case WSAENETDOWN: case WSAENETRESET: case WSAESHUTDOWN: case WSAECONNABORTED: case WSAETIMEDOUT: case WSAECONNRESET: { closesocket(t->s); t->s = -1; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); t->state = DKIP_STATE_OVER; } break; } TRANSL(t->error_code,recvfrom_error_translation); } } else { $? ". connection oriented" back = 1; if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { $? ". not non-blocking" if((t->flags) & DKIP_FLAG_TIMEOUT) { $? ". use timeout settings" $? ". have select" back = 0; to.tv_sec = (long)((t->to).seconds); to.tv_usec = (t->to).usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(t->s, &rfds); FD_SET(t->s, &efds); if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) { $? ". select succeeded" if((FD_ISSET(t->s, &rfds)) || (FD_ISSET(t->s, &efds))) { $? ". stream ready" back = 1; } else { $? "! stream not yet ready" t->error_code = DK_ERR_TIMED_OUT ; } } else { $? "! select failed" t->error_code = WSAGetLastError(); switch(t->error_code) { case WSAENETDOWN: { closesocket(t->s); t->s = -1; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); t->state = DKIP_STATE_OVER; } break; } TRANSL(t->error_code,recvfrom_error_translation); } } } if(back) { back = 0; xlgt = (int)recv(t->s, buf, *lgt, 0); $? "%d bytes", xlgt if(xlgt >= 0) { back = 1; *lgt = (size_t)xlgt; if(xlgt == 0) { if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { t->flags |= DKIP_FLAG_RDCLOSED; } } } else { $? "! recv failed" t->error_code = WSAGetLastError(); switch(t->error_code) { case WSAENETDOWN: case WSAENETRESET: case WSAESHUTDOWN: case WSAECONNABORTED: case WSAETIMEDOUT: case WSAECONNRESET: { closesocket(t->s); t->s = -1; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); t->state = DKIP_STATE_OVER; } break; } TRANSL(t->error_code,recvfrom_error_translation); } } } } else { t->error_code = DK_ERR_NOT_NOW; } } #endif #endif } break; default: { if(t) t->error_code = DK_ERR_NOT_NOW; } break; } } else { if(t) t->error_code = DK_ERR_INVALID_ARGS; } $? "- dktcpip_read %d", back return back; } int dktcpip_is_rdclosed DK_P1(dk_tcpip_t *, t) { int back = 0; $? "+ dktcpip_is_rdclosed %s", TR_PTR(t) if(t) { switch(t->state) { case DKIP_STATE_OPENED : { if(!((t->flags) & DKIP_FLAG_CONLESS)) { if((t->flags) & DKIP_FLAG_RDCLOSED) { back = 1; } } } break; default : { t->error_code = DK_ERR_NOT_NOW; } break; } } $? "- dktcpip_is_rdclosed %d", back return back; } int dktcpip_write DK_P3(dk_tcpip_t *, t, char *, buf, size_t *, lgt) { int back = 0; int xlgt; #if DK_HAVE_SELECT fd_set rfds, wfds, efds; struct timeval to; #endif $? "+ dktcpip_write %s %s %s", TR_PTR(t), TR_PTR(buf), TR_PTR(lgt) if(t && buf && lgt) { $? ". length %lu", (unsigned long)(*lgt) switch(t->state) { case DKIP_STATE_OPENED : { #if DK_HAVE_SYS_SOCKET_H if(!((t->flags) & DKIP_FLAG_WRCLOSED)) { if((t->flags) & DKIP_FLAG_CONLESS) { (t->a).r.w.ip4.sin.sin_port = dkenc_htons((t->a).r.w.ip4.portmin); xlgt = (int)sendto(t->s, buf, *lgt, 0, ((struct sockaddr *)(&((t->a).r.w.ip4.sin))), sizeof(SOIN)); if(xlgt >= 0) { back = 1; *lgt = (size_t)xlgt; } else { $? "! sendto failed" t->error_code = TRANSL(errno,sendto_error_translation); } } else { back = 1; if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { if((t->flags) & DKIP_FLAG_TIMEOUT) { #if DK_HAVE_SELECT back = 0; to.tv_sec = (long)((t->to).seconds); to.tv_usec = (t->to).usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(t->s, &wfds); if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) { if((FD_ISSET(t->s, &wfds)) || (FD_ISSET(t->s, &efds))) { back = 1; } else { t->error_code = DK_ERR_TIMED_OUT; } } else { t->error_code = TRANSL(errno,select_error_translation); } #endif } } if(back) { back = 0; xlgt = (int)send(t->s, buf, *lgt, 0); if(xlgt >= 0) { back = 1; *lgt = (size_t)xlgt; } else { $? "! send failed" switch(errno) { #ifdef ECONNRESET case ECONNRESET: { close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); } break; #endif #ifdef ENETDOWN case ENETDOWN: { close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); } break; #endif #ifdef ETIMEDOUT case ETIMEDOUT : { close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); } break; #endif } t->error_code = TRANSL(errno,send_error_translation); } } } } #else #if DK_HAVE_WINSOCK2_H if(started_successfully) { if(!((t->flags) & DKIP_FLAG_WRCLOSED)) { $? ". not yet finished" if((t->flags) & DKIP_FLAG_CONLESS) { $? ". connectionless" (t->a).r.w.ip4.sin.sin_port = dkenc_htons((t->a).r.w.ip4.portmin); xlgt = (int)sendto(t->s, buf, *lgt, 0, ((struct sockaddr *)(&((t->a).r.w.ip4.sin))), sizeof(SOIN)); if(xlgt >= 0) { back = 1; *lgt = (size_t)xlgt; } else { $? "! sendto failed" t->error_code = WSAGetLastError(); switch(t->error_code) { case WSAENETDOWN: case WSAENETRESET: case WSAESHUTDOWN: case WSAECONNABORTED: case WSAETIMEDOUT: case WSAECONNRESET: { closesocket(t->s); t->s = -1; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); t->state = DKIP_STATE_OVER; } break; } TRANSL(t->error_code,recvfrom_error_translation); } } else { $? ". connection-oriented" back = 1; if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { if((t->flags) & DKIP_FLAG_TIMEOUT) { back = 0; to.tv_sec = (long)((t->to).seconds); to.tv_usec = (t->to).usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(t->s, &wfds); if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) { if((FD_ISSET(t->s, &wfds)) || (FD_ISSET(t->s, &efds))) { back = 1; } else { t->error_code = DK_ERR_TIMED_OUT; } } else { t->error_code = WSAGetLastError(); switch(t->error_code) { case WSAENETDOWN: { closesocket(t->s); t->s = -1; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); t->state = DKIP_STATE_OVER; } break; } TRANSL(t->error_code,recvfrom_error_translation); } } } if(back) { back = 0; xlgt = (int)send(t->s, buf, *lgt, 0); if(xlgt >= 0) { back = 1; *lgt = (size_t)xlgt; } else { $? "! send failed" t->error_code = WSAGetLastError(); switch(t->error_code) { case WSAENETDOWN: case WSAENETRESET: case WSAESHUTDOWN: case WSAECONNABORTED: case WSAETIMEDOUT: case WSAECONNRESET: { closesocket(t->s); t->s = -1; t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); t->state = DKIP_STATE_OVER; } break; } TRANSL(t->error_code,recvfrom_error_translation); } } } } else { $? "! too late" t->error_code = DK_ERR_NOT_NOW; } } #endif #endif } break; default : { t->error_code = DK_ERR_NOT_NOW; } break; } } $? "- tcpip_write %d", back return back; } int dktcpip_closewrite DK_P1(dk_tcpip_t *, t) { int back = 0; $? "+ dktcpip_closewrite %s", TR_PTR(t) if(t) { #if DK_HAVE_SYS_SOCKET_H switch(t->state) { case DKIP_STATE_OPENED : { if(!((t->flags) & DKIP_FLAG_WRCLOSED)) { if(!((t->flags) & DKIP_FLAG_CONLESS)) { #ifdef SHUT_WR shutdown(t->s, SHUT_WR); #else shutdown(t->s, 1); #endif t->flags |= DKIP_FLAG_WRCLOSED; back = 1; } else { t->error_code = DK_ERR_NOT_NOW ; } } else { t->error_code = DK_ERR_NOT_NOW ; } } break; default : { t->error_code = DK_ERR_NOT_NOW ; } break; } #else #if DK_HAVE_WINSOCK2_H if(started_successfully) { switch(t->state) { case DKIP_STATE_OPENED : { if(!((t->flags) & DKIP_FLAG_WRCLOSED)) { if(!((t->flags) & DKIP_FLAG_CONLESS)) { shutdown(t->s, SD_SEND); t->flags |= DKIP_FLAG_WRCLOSED; back = 1; } else { t->error_code = DK_ERR_NOT_NOW ; } } else { t->error_code = DK_ERR_NOT_NOW ; } } break; default: { t->error_code = DK_ERR_NOT_NOW ; } break; } } #endif #endif } $? "- dktcpip_closewrite %d", back return back; } int dktcpip_up DK_P1(dk_tcpip_t *, t) { int back = 0; #ifdef O_NONBLOCK int xfl; #endif unsigned short x; int no_chance; #if DK_HAVE_WINSOCK2_H || DK_HAVE_SYS_SOCKET_H struct sockaddr_in tempaddr; dk_socklen_t optlgt; #endif #if DK_HAVE_WINSOCK2_H unsigned long set_nonblocking = 1UL; unsigned long unset_nonblocking = 0UL; #endif #if DK_HAVE_SELECT fd_set rfds, wfds, efds; struct timeval to; #endif $? "+ dktcpip_up" if(t) { no_chance = 0; switch(t->state) { case DKIP_STATE_NEW : { #if DK_HAVE_SYS_SOCKET_H $? ". BSD sockets" DK_MEMCPY(&((t->a).l.f),&((t->a).l.w),sizeof(dk_ip_addr_t)) ; t->s = socket(AF_INET, (((t->flags) & DKIP_FLAG_CONLESS) ? SOCK_DGRAM : SOCK_STREAM), 0); if((t->s) > -1) { if((t->flags) & DKIP_FLAG_REUSE) { $? ". mark address for reuse" set_reuse(t->s, 1); } if((t->flags) & (DKIP_FLAG_NONBLOCK | DKIP_FLAG_TIMEOUT)) { $? ". set nonblocking" #if DK_HAVE_FCNTL #ifdef O_NONBLOCK $? ". macros for nonblocking ok" xfl = fcntl(t->s, F_GETFL); xfl |= O_NONBLOCK; fcntl(t->s, F_SETFL, xfl); #endif #endif } if((t->flags) & DKIP_FLAG_BROADCAST) { if((t->flags) & DKIP_FLAG_CONLESS) { set_broadcast(t->s, 1); } } if((t->flags) & DKIP_FLAG_KEEPALIVE) { set_keepalive(t->s, 1); } x = (t->a).l.f.ip4.portmin; while((x <= (t->a).l.f.ip4.portmax) && (!back)) { (t->a).l.f.ip4.sin.sin_port = dkenc_htons(x); if(bind(t->s, ((struct sockaddr *)(&((t->a).l.f.ip4.sin))), sizeof(SOIN)) == 0) { back = 1; optlgt = sizeof(SOIN); if(getsockname(t->s, ((struct sockaddr *)(&tempaddr)), &optlgt) == 0) { DK_MEMCPY((&((t->a).l.f.ip4.sin)),(&tempaddr),sizeof(SOIN)); $? ". getsockname ok" } else { DK_MEMCPY((&((t->a).l.f.ip4.sin)),(&tempaddr),sizeof(SOIN)); $? "! getsockname failed" } (t->a).l.f.ip4.portmin = (t->a).l.f.ip4.portmax = dkenc_ntohs((t->a).l.f.ip4.sin.sin_port); $? ". local port %d bound (%d)", (int)((t->a).l.f.ip4.portmin), x } x++; } if(back) { if(!((t->flags) & DKIP_FLAG_CONLESS)) { $? ". connection" back = 0; x = (t->a).r.w.ip4.portmin; while((x <= (t->a).r.w.ip4.portmax) && (!back) && (!no_chance)) { $? ". start of connect loop" (t->a).r.w.ip4.sin.sin_port = dkenc_htons(x); if(connect(t->s, ((struct sockaddr *)(&((t->a).r.w.ip4.sin))), sizeof(SOIN)) == 0) { $? ". connect ok" back = 1; DK_MEMCPY(&((t->a).r.f), &((t->a).r.w), sizeof(dk_ip_addr_t)) ; } else { $? "! failed to connect to port %u reason %d", x, errno if(errno == EINPROGRESS) { no_chance = 1; if((t->flags) & DKIP_FLAG_TIMEOUT) { #if DK_HAVE_SELECT to.tv_sec = (long)((t->to).seconds); to.tv_usec = (t->to).usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(t->s, &wfds); if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) { if((FD_ISSET(t->s, &wfds)) || (FD_ISSET(t->s, &efds))) { back = 1; } else { t->error_code = DK_ERR_TIMED_OUT; } } else { t->error_code = TRANSL(errno,select_error_translation); } #endif } else { back = 1; } } } x++; } } if(back) { t->state = DKIP_STATE_OPENED; t->flags &= (~(DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED)); if((t->flags) & DKIP_FLAG_TIMEOUT) { if(!((t->flags) & DKIP_FLAG_NONBLOCK)) { #if DK_HAVE_FCNTL #ifdef O_NONBLOCK xfl = fcntl(t->s, F_GETFL); xfl &= (~(O_NONBLOCK)); fcntl(t->s, F_SETFL, xfl); #else $? "! no O_NONBLOCK" #endif #else $? "! no fcntl" #endif } } } else { $? "! connect failed" t->error_code = TRANSL(errno,connect_error_translation); close(t->s); t->s = -1; } } else { $? "! bind failed" t->error_code = TRANSL(errno,bind_error_translation); close(t->s); t->s = -1; } } else { $? "! socket failed" t->error_code = TRANSL(errno,socket_error_translation); } #else #if DK_HAVE_WINSOCK2_H $? ". Winsock" if(started_successfully) { $? ". winsock available" DK_MEMCPY(&((t->a).l.f),&((t->a).l.w),sizeof(dk_ip_addr_t)) ; t->s = socket(AF_INET, (((t->flags) & DKIP_FLAG_CONLESS) ? SOCK_DGRAM : SOCK_STREAM), 0); if((t->s) != INVALID_SOCKET) { $? ". socket() ok" if((t->flags) & DKIP_FLAG_REUSE) { $? ". mark address for reuse" set_reuse(t->s, 1); } if((t->flags) & (DKIP_FLAG_NONBLOCK | DKIP_FLAG_TIMEOUT)) { $? ". set nonblocking" ioctlsocket(t->s, FIONBIO, &set_nonblocking); } if((t->flags) & DKIP_FLAG_BROADCAST) { if((t->flags) & DKIP_FLAG_CONLESS) { $? ". set broadcast" set_broadcast(t->s, 1); } } if((t->flags) & DKIP_FLAG_KEEPALIVE) { $? ". set keepalive" set_keepalive(t->s, 1); } x = (t->a).l.f.ip4.portmin; while((x <= (t->a).l.f.ip4.portmax) && (!back)) { (t->a).l.f.ip4.sin.sin_port = dkenc_htons(x); if(bind(t->s, ((struct sockaddr *)(&((t->a).l.f.ip4.sin))), sizeof(SOIN)) == 0) { back = 1; optlgt = sizeof(SOIN); if(getsockname(t->s, ((struct sockaddr *)(&tempaddr)), &optlgt) == 0) { DK_MEMCPY((&((t->a).l.f.ip4.sin)),(&tempaddr),sizeof(SOIN)); $? ". getsockname ok" } else { DK_MEMCPY((&((t->a).l.f.ip4.sin)),(&tempaddr),sizeof(SOIN)); $? "! getsockname failed" } (t->a).l.f.ip4.portmin = (t->a).l.f.ip4.portmax = dkenc_ntohs((t->a).l.f.ip4.sin.sin_port); $? ". local port %d bound", (int)x $? ". getsockname -> %d", (int)((t->a).l.f.ip4.portmin) } else { $? "! failed to bind local port %d", (int)x } x++; } if(back) { if(!((t->flags) & DKIP_FLAG_CONLESS)) { $? ". connection" back = 0; x = (t->a).r.w.ip4.portmin; while((x <= (t->a).r.w.ip4.portmax) && (!back) && (!no_chance)) { $? ". start of connect loop" (t->a).r.w.ip4.sin.sin_port = dkenc_htons(x); if(connect(t->s, ((struct sockaddr *)(&((t->a).r.w.ip4.sin))), sizeof(SOIN)) == 0) { $? ". connected to remote port %d", (int)x back = 1; DK_MEMCPY(&((t->a).r.f), &((t->a).r.w), sizeof(dk_ip_addr_t)) ; } else { t->error_code = WSAGetLastError(); $? ". connect attempt failed %d", t->error_code if(t->error_code == WSAEWOULDBLOCK) { $? "! operation would block" no_chance = 1; if((t->flags) & DKIP_FLAG_TIMEOUT) { $? ". timeout flag set" to.tv_sec = (long)((t->to).seconds); to.tv_usec = (t->to).usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(t->s, &wfds); $? ". calling select" if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) { $? ". select succeeded" if((FD_ISSET(t->s, &wfds)) || (FD_ISSET(t->s, &efds))) { back = 1; $? ". select ok" } else { t->error_code = DK_ERR_TIMED_OUT; $? "! we are timed out" } } else { t->error_code = WSAGetLastError(); $? "! select failed %d", t->error_code } } else { back = 1; $? "! timeout flag not set" } } else { $? "! failed for other reason" } } x++; } } if(back) { $? ". connected successfully" t->state = DKIP_STATE_OPENED; t->flags &= (~(DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED)); if((t->flags) & DKIP_FLAG_TIMEOUT) { if(!((t->flags) & DKIP_FLAG_TIMEOUT)) { ioctlsocket(t->s, FIONBIO, (unsigned long *)NULL); } } } else { $? ". WSA... already received" $? "! connect failed %d", t->error_code t->error_code = TRANSL(t->error_code,connect_error_translation); closesocket(t->s); t->s = -1; } } else { t->error_code = WSAGetLastError(); $? "! bind failed %d", t->error_code t->error_code = TRANSL(t->error_code,bind_error_translation); closesocket(t->s); t->s = -1; } } else { t->error_code = WSAGetLastError(); $? "! socket() = %d failed %d", t->s, t->error_code t->error_code = TRANSL(t->error_code,socket_error_translation); } } else { $? "! winsock not yet available" t->error_code = DK_ERR_NOT_NOW; } #endif #endif } break; } } $? "- dktcpip_up %d", back return back; } int dktcpip_down DK_P1(dk_tcpip_t *, t) { int back = 0; $? "+ dktcpip_down %s", TR_PTR(t) if(t) { #if DK_HAVE_SYS_SOCKET_H switch(t->state) { case DKIP_STATE_OPENED : { if(!((t->flags) & DKIP_FLAG_CONLESS)) { switch((t->flags) & (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED)) { case 0 : { #ifdef SHUT_RDWR shutdown(t->s, SHUT_RDWR); #else shutdown(t->s, 2); #endif } break; case DKIP_FLAG_RDCLOSED : { #ifdef SHUT_WR shutdown(t->s, SHUT_WR); #else shutdown(t->s, 1); #endif } break; case DKIP_FLAG_WRCLOSED : { #ifdef SHUT_RD shutdown(t->s, SHUT_RD); #else shutdown(t->s, 0); #endif } break; } } t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); close(t->s); t->s = -1; t->state = DKIP_STATE_OVER; } break; } #else #if DK_HAVE_WINSOCK2_H switch(t->state) { case DKIP_STATE_OPENED: { if(started_successfully) { if(!((t->flags) & DKIP_FLAG_CONLESS)) { switch((t->flags) & (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED)) { case 0 : { shutdown(t->s, SD_BOTH); } break; case DKIP_FLAG_RDCLOSED : { shutdown(t->s, SD_SEND); } break; case DKIP_FLAG_WRCLOSED : { shutdown(t->s, SD_RECEIVE); } break; } } t->flags |= (DKIP_FLAG_RDCLOSED | DKIP_FLAG_WRCLOSED); closesocket(t->s); t->s = -1; t->state = DKIP_STATE_OVER; } } break; } #endif #endif } $? "- dktcpip_down %d", back return back; } int dktcpip_set_nonblock DK_P2(dk_tcpip_t *, t, int, fl) { int back = 0; #if DK_HAVE_SYS_SOCKET_H #if DK_HAVE_FCNTL #ifdef O_NONBLOCK int xfl; #endif #endif #else #if DK_HAVE_WINSOCK2_H unsigned long set_nonblocking = 1UL; #endif #endif $? "+ dktcpip_set_nonblock %s %d", TR_PTR(t), fl if(t) { switch(t->state) { case DKIP_STATE_NEW : { if(fl) { t->flags |= DKIP_FLAG_NONBLOCK; } else { t->flags &= (~(DKIP_FLAG_NONBLOCK)); } back = 1; } break; case DKIP_STATE_OPENED : { if(fl) { t->flags |= DKIP_FLAG_NONBLOCK; #if DK_HAVE_SYS_SOCKET_H #if DK_HAVE_FCNTL #ifdef O_NONBLOCK $? ". macros for nonblocking ok" if((t->s) > -1) { xfl = fcntl(t->s, F_GETFL); xfl |= O_NONBLOCK ; fcntl(t->s, F_SETFL, xfl); back = 1; } #else $? "! no O_NONBLOCK" #endif #else $? "! no fcntl()" #endif #else #if DK_HAVE_WINSOCK2_H ioctlsocket(t->s, FIONBIO, &set_nonblocking); #endif #endif } else { t->flags &= (~(DKIP_FLAG_NONBLOCK)); #if DK_HAVE_SYS_SOCKET_H #if DK_HAVE_FCNTL #ifdef O_NONBLOCK $? ". macros for nonblocking ok" if((t->s) > -1) { xfl = fcntl(t->s, F_GETFL); xfl &= (~(O_NONBLOCK)) ; fcntl(t->s, F_SETFL, xfl); back = 1; } #endif #endif #else #if DK_HAVE_WINSOCK2_H ioctlsocket(t->s, FIONBIO, NULL); #endif #endif } } break; } } $? "- dktcpip_set_nonblock %d", back return back; } int dktcpip_set_timeout DK_P2(dk_tcpip_t *, t, double, to) { int back = 0; unsigned long ul1, ul2; double x, xr; int ok; $? "+ dktcpip_set_timeout %s %lf", TR_PTR(t), to #if DK_HAVE_SELECT if(t) { if(to != 0.0) { ok = 0; x = fabs(to); xr = dkma_rint(x); ul1 = dkma_double_to_ul_ok(x, &ok); x = x - xr; x = dkma_mul_double_ok(x, 1000000.0, &ok); ul2 = dkma_double_to_ul_ok(x, &ok); if(!ok) { (t->to).seconds = (time_t)ul1; (t->to).usecs = (long)ul2; back = 1; t->flags |= DKIP_FLAG_TIMEOUT; } } else { t->flags &= (~(DKIP_FLAG_TIMEOUT)); } } #endif $? "- dktcpip_set_timeout %d", back return back; } int dktcpip_respond DK_P1(dk_tcpip_t *, t) { int back = 0; $? "+ dktcpip_respond %s", TR_PTR(t) if(t) { switch(t->state) { case DKIP_STATE_OPENED : { if((t->flags) & DKIP_FLAG_CONLESS) { back = 1; DK_MEMCPY(&((t->a).r.w),&((t->a).r.f),sizeof(dk_ip_addr_t)) ; } } break; } } $? "- dktcpip_respond %d", back return back; } int dktcpip_end DK_P0() { int back = 0; $? "+ dktcpip_end" #if DK_HAVE_SYS_SOCKET_H back = 1; #else #if DK_HAVE_WINSOCK2_H if(started_successfully) { if(number_of_starts == 1UL) { back = WSACleanup(); back = (back ? 0 : 1); } } if(number_of_starts > 0UL) { number_of_starts--; } #else #endif #endif $? "- dktcpip_end %d", back return back; } int dktcpip_get_error_code DK_P2(dk_tcpip_t *, t, int, cl) { int back = 0; if(t) { back = t->error_code; if(cl) { t->error_code = 0; } } return back; }