/*
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 <math.h>



/**	Inside the dktcpip module.
*/
#define DK_TCPIP_C 1

#include "dktcpip.h"



#if DK_HAVE_STRING_H
#include <string.h>
#endif
#if DK_HAVE_CTYPE_H
#include <ctype.h>
#endif
#if DK_HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#if DK_HAVE_NETDB_H
#include <netdb.h>
#endif
#if DK_HAVE_ERRNO_H
#include <errno.h>
#endif
#if DK_HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if DK_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if DK_HAVE_STDLIB_H
#include <stdlib.h>
#endif


#line 89 "dktcpip.ctr"




/**	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)
{
  
  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);
  } 
}



/**	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; 
  if(t >= 0) {
    opt = (fl ?  1 : 0);
    status=setsockopt(t,SOL_SOCKET,SO_REUSEADDR,((char *)(&opt)),sizeof(opt));
    
    back = ((status == 0) ? 1 : 0);
  } 
#else
  
#endif
#else
  
#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; 
  if(t >= 0) {
    opt = (fl ?  1 : 0);
    status=setsockopt(t,SOL_SOCKET,SO_BROADCAST,((char *)(&opt)),sizeof(opt));
    
    back = ((status == 0) ? 1 : 0);
  } 
#else
  
#endif
#else
  
#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; 
  if(t >= 0) {
    opt = (fl ?  1 : 0);
    status=setsockopt(t,SOL_SOCKET,SO_KEEPALIVE,((char *)(&opt)),sizeof(opt));
    
    back = ((status == 0) ? 1 : 0);
  } 
#else
  
#endif
#else
  
#endif
  return back;
}



int
dktcpip_set_reuse DK_P2(dk_tcpip_t *, t, int, fl)
{
  int back = 0;
  
  if(t) {
    switch(t->state) {
      case DKIP_STATE_NEW : {
	if(fl) {
	  t->flags |= DKIP_FLAG_REUSE;
	} else {
	  t->flags &= (~(DKIP_FLAG_REUSE));
	} 
	back = 1;
      } break;
      case DKIP_STATE_OPENED : {
	if(fl) {
	  t->flags |= DKIP_FLAG_REUSE;
	} else {
	  t->flags &= (~(DKIP_FLAG_REUSE));
	} 
	back = set_reuse(t->s, fl);
      } break;
    }
  } 
  return back;
}



int
dktcpip_set_broadcast DK_P2(dk_tcpip_t *, t, int, fl)
{
  int back = 0;
  
  if(t) {
    switch(t->state) {
      case DKIP_STATE_NEW : {
	if(fl) {
	  t->flags |= DKIP_FLAG_BROADCAST;
	} else {
	  t->flags &= (~(DKIP_FLAG_BROADCAST));
	} 
	back = 1;
      } break;
      case DKIP_STATE_OPENED : {
	if(fl) {
	  t->flags |= DKIP_FLAG_BROADCAST;
	} else {
	  t->flags &= (~(DKIP_FLAG_BROADCAST));
	} 
	if((t->flags) & DKIP_FLAG_CONLESS) {
	  back = set_broadcast(t->s, fl);
	} else {
	  back = 1;
	}
      } break;
    }
  } 
  return back;
}



int
dktcpip_set_keepalive DK_P2(dk_tcpip_t *, t, int, fl)
{
  int back = 0;
  
  if(t) {
    switch(t->state) {
      case DKIP_STATE_NEW : {
	if(fl) {
	  t->flags |= DKIP_FLAG_KEEPALIVE;
	} else {
	  t->flags &= (~(DKIP_FLAG_KEEPALIVE));
	} 
	back = 1;
      } break;
      case DKIP_STATE_OPENED : {
	if(fl) {
	  t->flags |= DKIP_FLAG_KEEPALIVE;
	} else {
	  t->flags &= (~(DKIP_FLAG_KEEPALIVE));
	} 
	back = set_keepalive(t->s, fl);
      } break;
    }
  } 
  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;
  
  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;
  
  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
  
  if(a && hn) {
#if DK_HAVE_GETHOSTBYNAME
    hp = gethostbyname(hn);
    if(hp) { 
      if(hp->h_addr_list) { 
	if(hp->h_length) { 
	  lp = (unsigned long *)(*(hp->h_addr_list));
	  if(lp) { 
	    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;
  } 
  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
  
  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) { 
        if(hp->h_addr_list) { 
	  if(hp->h_length) { 
	    lp = (unsigned long *)(*(hp->h_addr_list));
	    if(lp) { 
	      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) */
  
  
  return back;
}

#endif
/* DNS_LOOKUP_FIRST */


int
dktcpipaddr_set_ip_loopback DK_P1(dk_ip_addr_t *, a)
{
  int back = 0;
  
  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
  } 
  return back;
}



int
dktcpipaddr_set_ip_local DK_P2(dk_ip_addr_t *, a, dk_tcpip_t *, p)
{
  int back = 0;
  char *hostname;
  
  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;
  }
  
  return back;
}



int
dktcpipaddr_set_ip_any DK_P1(dk_ip_addr_t *, a)
{
  int back = 0;
  
  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
  } 
  return back;
}



void
dktcpip_init DK_P1(dk_tcpip_t *,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;
  } 
}



dk_tcpip_t *
dktcpip_new DK_P0()
{
  dk_tcpip_t *back = NULL;
  
  back = dk_new(dk_tcpip_t,1);
  if(back) {
    dktcpip_init(back);
  } 
  return back;
}



void
dktcpip_delete DK_P1(dk_tcpip_t *, p)
{
  
  if(p) {
    (void)dktcpip_down(p);
    dk_delete(p);
  } 
}



int
dktcpip_start DK_P0()
{
  int back = 0;
#if DK_HAVE_SYS_SOCKET_H
  
  
  back = 1;
#else
#if DK_HAVE_WINSOCK2_H
  WORD version_requested;
  WSADATA wsa_data;
  
  
  if(number_of_starts == 0UL) {
    
    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
  
  return back;
}



int
dktcpip_set_connectionless DK_P2(dk_tcpip_t *, p, int, flag)
{
  int back = 0;
  
  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;
    }
  } 
  return back;
}


int
dktcpip_addr_set_port DK_P3(dk_ip_addr_t *, a, unsigned short, min, unsigned short, max)
{
  int back = 0;
  
  if(a) {
    back = 1;
    (a->ip4).portmin = min;
    (a->ip4).portmax = max;
  } 
  return back;
}



dk_ip_addr_t *
dktcpip_get_addr DK_P2(dk_tcpip_t *, p, int, w)
{
  dk_ip_addr_t *back = NULL;
  
  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;
    }
  } 
  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
  
  if(t && buf && 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 { 
	  t->error_code = TRANSL(errno,recvfrom_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, &rfds);
	    FD_SET(t->s, &efds);
	    if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) {
	      
	      if((FD_ISSET(t->s, &rfds)) || (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 {
	  
	}
	if(back) { 
	  back = 0;
	  xlgt = (int)recv(t->s, buf, *lgt, 0); 
	  if(xlgt >= 0) {
	    back = 1;
	    *lgt = (size_t)xlgt;
	    if(xlgt == 0) {
	      if(!((t->flags) & DKIP_FLAG_NONBLOCK)) {
		t->flags |= DKIP_FLAG_RDCLOSED;
	      }
	    }
	  } else { 
	    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) { 
	  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 { 
	    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 { 
	  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, &rfds);
	      FD_SET(t->s, &efds);
	      if(select(((t->s) + 1), &rfds, &wfds, &efds, &to) != -1) {
	        
	        if((FD_ISSET(t->s, &rfds)) || (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)recv(t->s, buf, *lgt, 0); 
	    if(xlgt >= 0) {
	      back = 1;
	      *lgt = (size_t)xlgt;
	      if(xlgt == 0) {
	        if(!((t->flags) & DKIP_FLAG_NONBLOCK)) {
		  t->flags |= DKIP_FLAG_RDCLOSED;
	        }
	      }
	    } else { 
	      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;
  } 
  return back;
}



int
dktcpip_is_rdclosed DK_P1(dk_tcpip_t *, t)
{
  int back = 0;
  
  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;
    }
  } 
  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
  
  if(t && buf && 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 { 
	  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 { 
	    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)) { 
	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 { 
	    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 { 
	  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 { 
	      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 : {
    t->error_code = DK_ERR_NOT_NOW;
  } break;
  }
  } 
  return back;
}



int
dktcpip_closewrite DK_P1(dk_tcpip_t *, t)
{
  int back = 0;
  
  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
  } 
  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
  
  if(t) {
    no_chance = 0;
    switch(t->state) {
      case DKIP_STATE_NEW : {
#if DK_HAVE_SYS_SOCKET_H
	
	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) {
	    
	    set_reuse(t->s, 1);
	  }
	  if((t->flags) & (DKIP_FLAG_NONBLOCK | DKIP_FLAG_TIMEOUT)) {
	    
#if DK_HAVE_FCNTL
#ifdef O_NONBLOCK
	    
	    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));
		
	      } else {
		DK_MEMCPY((&((t->a).l.f.ip4.sin)),(&tempaddr),sizeof(SOIN));
		
	      }
	      (t->a).l.f.ip4.portmin = (t->a).l.f.ip4.portmax =
	      dkenc_ntohs((t->a).l.f.ip4.sin.sin_port);
	      
	    }
	    x++;
	  }
	  if(back) {
	    if(!((t->flags) & DKIP_FLAG_CONLESS)) { 
	      back = 0;
	      x = (t->a).r.w.ip4.portmin;
	      while((x <= (t->a).r.w.ip4.portmax) && (!back) && (!no_chance)) {
		
		(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) {
		  
		  back = 1;
		  DK_MEMCPY(&((t->a).r.f), &((t->a).r.w), sizeof(dk_ip_addr_t)) ;
		} else {
		  
		  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
		  
#endif
#else
		  
#endif
		}
	      }
	    } else { 
	      t->error_code = TRANSL(errno,connect_error_translation);
	      close(t->s);
	      t->s = -1;
	    }
	  } else { 
	    t->error_code = TRANSL(errno,bind_error_translation);
	    close(t->s);
	    t->s = -1;
	  }
	} else { 
	  t->error_code = TRANSL(errno,socket_error_translation);
	}
#else
#if DK_HAVE_WINSOCK2_H
	
	if(started_successfully) {
	  
	  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) {
	    
	    if((t->flags) & DKIP_FLAG_REUSE) {
	      
	      set_reuse(t->s, 1);
	    }
	    if((t->flags) & (DKIP_FLAG_NONBLOCK | DKIP_FLAG_TIMEOUT)) {
	      
	      ioctlsocket(t->s, FIONBIO, &set_nonblocking);
	    }
	    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));
		  
	        } else {
		  DK_MEMCPY((&((t->a).l.f.ip4.sin)),(&tempaddr),sizeof(SOIN));
		  
	        }
	        (t->a).l.f.ip4.portmin = (t->a).l.f.ip4.portmax =
	        dkenc_ntohs((t->a).l.f.ip4.sin.sin_port);
		
		
	      } else {
		
	      }
	      x++;
	    }
	    if(back) {
	      if(!((t->flags) & DKIP_FLAG_CONLESS)) { 
		back = 0;
		x = (t->a).r.w.ip4.portmin;
		while((x <= (t->a).r.w.ip4.portmax) && (!back) && (!no_chance)) {
		  
		  (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) {
		    
		    back = 1;
		    DK_MEMCPY(&((t->a).r.f), &((t->a).r.w), sizeof(dk_ip_addr_t)) ;
		  } else {
		    t->error_code = WSAGetLastError();
		    
		    if(t->error_code == WSAEWOULDBLOCK) {
		      
		      no_chance = 1;
		      if((t->flags) & DKIP_FLAG_TIMEOUT) {
			
	                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();
			  
	                }
		      } else {
			back = 1;
			
		      }
		    } else { 
		    }
		  }
		  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_TIMEOUT)) {
		    ioctlsocket(t->s, FIONBIO, (unsigned long *)NULL);
		  }
		}
	      } else {
		
		
		t->error_code = TRANSL(t->error_code,connect_error_translation);
		closesocket(t->s);
		t->s = -1;
	      }
	    } else {
	      t->error_code = WSAGetLastError();
	      
	      t->error_code = TRANSL(t->error_code,bind_error_translation);
	      closesocket(t->s);
	      t->s = -1;
	    }
	  } else {
	    t->error_code = WSAGetLastError();
	    
	    t->error_code = TRANSL(t->error_code,socket_error_translation);
	  }
	} else {
	  
	  t->error_code = DK_ERR_NOT_NOW;
	}
#endif
#endif
      } break;
    }
  } 
  return back;
}



int
dktcpip_down DK_P1(dk_tcpip_t *, t)
{
  int back = 0;
  
  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
  } 
  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
  
  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
	  
	  if((t->s) > -1) {
	  xfl = fcntl(t->s, F_GETFL);
	  xfl |= O_NONBLOCK ;
	  fcntl(t->s, F_SETFL, xfl);
	  back = 1;
	  }
#else
	  
#endif
#else
	  
#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
	  
	  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;
    }
  } 
  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;
  
#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
  
  return back;
}



int
dktcpip_respond DK_P1(dk_tcpip_t *, t)
{
  int back = 0;
  
  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;
    } 
  } 
  return back;
}



int
dktcpip_end DK_P0()
{
  int back = 0;
  
#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
  
  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;
}



