requestAssociationTCP(PRIVATE_NETWORKKEY ** network,
                      DUL_ASSOCIATESERVICEPARAMETERS * params,
                      PRIVATE_ASSOCIATIONKEY ** association)
{
    char node[128];
    int  port;
    OFSockAddr server;
#ifdef _WIN32
    SOCKET s;
#else
    int s;
#endif
    struct linger sockarg;

    if (sscanf(params->calledPresentationAddress, "%[^:]:%d", node, &port) != 2)
    {
        char buf[1024];
        sprintf(buf,"Illegal service parameter: %s", params->calledPresentationAddress);
        return makeDcmnetCondition(DULC_ILLEGALSERVICEPARAMETER, OF_error, buf);
    }

    /*
     * At least officially, gethostbyname will not accept an IP address on many
     * operating systems (e.g. Windows or FreeBSD), so we need to explicitly
     * handle the IP address case.
     */
    unsigned long addr = inet_addr(node);
    if (addr != INADDR_NONE)
    {
        // it is an IPv4 address
        server.setFamily(AF_INET);
        struct sockaddr_in *sa = server.getSockaddr_in();
        sa->sin_addr.s_addr = addr;
    }
    else
    {
        // must be a host name or an IPv6 address
        OFStandard::getAddressByHostname(node, server);
        if (server.getFamily() == 0)
        {
          char buf2[4095]; // node could be a long string
          sprintf(buf2, "Attempt to connect to unknown host: %s", node);
          return makeDcmnetCondition(DULC_UNKNOWNHOST, OF_error, buf2);
        }
    }
    server.setPort(OFstatic_cast(unsigned short, htons(OFstatic_cast(unsigned short, port))));

    // get global connection timeout
    Sint32 connectTimeout = dcmConnectionTimeout.get();

    s = socket(server.getFamily(), SOCK_STREAM, 0);
#ifdef _WIN32
    if (s == INVALID_SOCKET)
#else
    if (s < 0)
#endif
    {
      OFString msg = "TCP Initialization Error: ";
      msg += OFStandard::getLastNetworkErrorCode().message();
      return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
    }

#ifdef HAVE_WINSOCK_H
    u_long arg = TRUE;
#else
    int flags = 0;
#endif

    if (connectTimeout >= 0)
    {
      // user has specified a timeout, switch socket to non-blocking mode
#ifdef HAVE_WINSOCK_H
      ioctlsocket(s, FIONBIO, (u_long FAR *) &arg);
#else
      flags = fcntl(s, F_GETFL, 0);
      fcntl(s, F_SETFL, O_NONBLOCK | flags);
#endif
    }

    // depending on the socket mode, connect will block or return immediately
    int rc;
    do {
        rc = connect(s, server.getSockaddr(), server.size());
    } while (rc == -1 && OFStandard::getLastNetworkErrorCode().value() == DCMNET_EINTR);

#ifdef HAVE_WINSOCK_H
    if (rc == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
#else
    if (rc < 0 && errno == EINPROGRESS)
#endif
    {
#ifndef DCMTK_HAVE_POLL
        // we're in non-blocking mode. Prepare to wait for timeout.
        fd_set fdSet;
        FD_ZERO(&fdSet);
#ifdef __MINGW32__
        // on MinGW, FD_SET expects an unsigned first argument
        FD_SET((unsigned int) s, &fdSet);
#else
        FD_SET(s, &fdSet);
#endif /* __MINGW32__ */
#endif /* DCMTK_HAVE_POLL */

        struct timeval timeout;
        timeout.tv_sec = connectTimeout;
        timeout.tv_usec = 0;

        do {
#ifdef DCMTK_HAVE_POLL
            struct pollfd pfd[] =
            {
                { s, POLLOUT, 0 }
            };
            rc = poll(pfd, 1, timeout.tv_sec*1000+(timeout.tv_usec/1000));
#else
            // the typecast is safe because Windows ignores the first select() parameter anyway
            rc = select(OFstatic_cast(int, s + 1), NULL, &fdSet, NULL, &timeout);
#endif
        } while (rc == -1 && OFStandard::getLastNetworkErrorCode().value() == DCMNET_EINTR);

        if (DCM_dcmnetLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
        {
            DU_logSelectResult(rc);
        }

        // reset socket to blocking mode
#ifdef HAVE_WINSOCK_H
        arg = FALSE;
        ioctlsocket(s, FIONBIO, (u_long FAR *) &arg);
#else
        fcntl(s, F_SETFL, flags);
#endif
        if (rc == 0)
        {
            // timeout reached, bail out with error return code
#ifdef HAVE_WINSOCK_H
            (void) shutdown(s,  1 /* SD_SEND */);
            (void) closesocket(s);
#else
            (void) close(s);
#endif
            (*association)->networkState = NETWORK_DISCONNECTED;
            if ((*association)->connection) delete (*association)->connection;
            (*association)->connection = NULL;

            OFString msg = "TCP Initialization Error: ";
            msg += OFStandard::getLastNetworkErrorCode().message();
            msg += " (Timeout)";
            return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
  }
#ifndef HAVE_WINSOCK_H
        else if (rc > 0)
        {
            // select reports that our connection request has proceeded.
            // This could either mean success or an asynchronous error condition.
            // use getsockopt to check the socket status.
            int socketError = 0;

#ifdef HAVE_DECLARATION_SOCKLEN_T
            // some platforms (e.g. Solaris 7) declare socklen_t
            socklen_t socketErrorLen = sizeof(socketError);
#elif defined(HAVE_INTP_GETSOCKOPT)
            // some platforms (e.g. Solaris 2.5.1) prefer int
            int socketErrorLen = (int) sizeof(socketError);
#else
            // some platforms (e.g. OSF1 4.0) prefer size_t
            size_t socketErrorLen = sizeof(socketError);
#endif

            // Solaris 2.5.1 expects a char * as argument 4 of getsockopt. Most other
            // platforms expect void *, so casting to a char * should be safe.
            getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)(&socketError), &socketErrorLen);
            if (socketError)
            {
                // asynchronous error on our socket, bail out.
                (void) close(s);
                (*association)->networkState = NETWORK_DISCONNECTED;
                if ((*association)->connection) delete (*association)->connection;
                (*association)->connection = NULL;

                char buf[256];
                OFString msg = "TCP Initialization Error: ";
                msg += OFStandard::strerror(socketError, buf, sizeof(buf));
                return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
            }
        }
#endif
    }
    else
    {
        // The connect() returned without using the select(), reset the socket if needed
        if (connectTimeout >= 0)
        {
            // reset socket to blocking mode
#ifdef HAVE_WINSOCK_H
            arg = FALSE;
            ioctlsocket(s, FIONBIO, (u_long FAR *) &arg);
#else
            fcntl(s, F_SETFL, flags);
#endif
        }
    }

    if (rc < 0)
    {
        // an error other than timeout in non-blocking mode has occurred,
        // either in connect() or in select().
#ifdef HAVE_WINSOCK_H
        (void) shutdown(s,  1 /* SD_SEND */);
        (void) closesocket(s);
#else
        (void) close(s);
#endif
        (*association)->networkState = NETWORK_DISCONNECTED;
        if ((*association)->connection) delete (*association)->connection;
        (*association)->connection = NULL;

        OFString msg = "TCP Initialization Error: ";
        msg += OFStandard::getLastNetworkErrorCode().message();
        return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
    } else {
        // success - we've opened a TCP transport connection

        (*association)->networkState = NETWORK_CONNECTED;
        if ((*association)->connection) delete (*association)->connection;

        if (network && (*network) && ((*network)->networkSpecific.TCP.tLayer))
        {
          (*association)->connection = ((*network)->networkSpecific.TCP.tLayer)->createConnection(s, params->useSecureLayer);
        }
        else (*association)->connection = NULL;

        if ((*association)->connection == NULL)
        {
#ifdef HAVE_WINSOCK_H
          (void) shutdown(s,  1 /* SD_SEND */);
          (void) closesocket(s);
#else
          (void) close(s);
#endif
          (*association)->networkState = NETWORK_DISCONNECTED;

          OFString msg = "TCP Initialization Error: ";
          msg += OFStandard::getLastNetworkErrorCode().message();
          return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
        }
        sockarg.l_onoff = 0;
        sockarg.l_linger = 0;

        if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &sockarg, (int) sizeof(sockarg)) < 0)
        {
          OFString msg = "TCP Initialization Error: ";
          msg += OFStandard::getLastNetworkErrorCode().message();
          return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
        }
        setTCPBufferLength(s);

        /*
         * Disable the so-called Nagle algorithm (if requested).
         * This might provide a better network performance on some systems/environments.
         * By default, the algorithm is not disabled unless DISABLE_NAGLE_ALGORITHM is defined.
         * The default behavior can be changed by setting the environment variable TCP_NODELAY.
         */

#ifdef DONT_DISABLE_NAGLE_ALGORITHM
#ifdef _MSC_VER
#pragma message("The macro DONT_DISABLE_NAGLE_ALGORITHM is not supported anymore. See 'macros.txt' for details.")
#else
#warning The macro DONT_DISABLE_NAGLE_ALGORITHM is not supported anymore. See "macros.txt" for details.
#endif
#endif

#ifdef DISABLE_NAGLE_ALGORITHM
        int tcpNoDelay = 1; // disable
#else
        int tcpNoDelay = 0; // don't disable
#endif
        char* tcpNoDelayString = NULL;
        DCMNET_TRACE("checking whether environment variable TCP_NODELAY is set");
        if ((tcpNoDelayString = getenv("TCP_NODELAY")) != NULL)
        {
          if (sscanf(tcpNoDelayString, "%d", &tcpNoDelay) != 1)
          {
            DCMNET_WARN("DULFSM: cannot parse environment variable TCP_NODELAY=" << tcpNoDelayString);
          }
        } else
          DCMNET_TRACE("  environment variable TCP_NODELAY not set, using the default value (" << tcpNoDelay << ")");
        if (tcpNoDelay) {
#ifdef DISABLE_NAGLE_ALGORITHM
          DCMNET_DEBUG("DULFSM: disabling Nagle algorithm as defined at compilation time (DISABLE_NAGLE_ALGORITHM)");
#else
          DCMNET_DEBUG("DULFSM: disabling Nagle algorithm as requested at runtime (TCP_NODELAY=" << tcpNoDelayString << ")");
#endif
          if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&tcpNoDelay, sizeof(tcpNoDelay)) < 0)
          {
            OFString msg = "TCP Initialization Error: ";
            msg += OFStandard::getLastNetworkErrorCode().message();
            return makeDcmnetCondition(DULC_TCPINITERROR, OF_error, msg.c_str());
          }
#ifdef DISABLE_NAGLE_ALGORITHM
        } else {
          DCMNET_DEBUG("DULFSM: do not disable Nagle algorithm as requested at runtime (TCP_NODELAY=" << tcpNoDelayString << ")");
#endif
        }

        return (*association)->connection->clientSideHandshake();
    }
}