/*
 * Copyright (c) 1989,
 * 	National Center for Atmospheric Research
 *
 */
#if !defined(LINT) && !defined(VX)
static char rcsid[]="$Header: /net/src3/btcl/tclTCP2.1/src/RCS/clntStrmSock.c,v 1.3 1994/08/04 13:26:53 vanandel Exp $";
#endif

/* TkWin version 0.3 -- Tk for Windows
 * Copyright (C) 1994 K. K. Kubota
 * Mathematical Sciences Computing Facility, University of Kentucky,
 * Lexington, KY 40506, USA (e-mail: ken@ms.uky.edu)
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose is granted without fee, provided that the above copyright notice
 * and the following paragraph appear in all copies of this software
 * and supporting documentation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY, even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  In no event shall the author be
 * liable to any party for direct, indirect, special, incidental, or
 * consequential damages arising out of the use of this software and its
 * documentation.
 */

/*
 * Revision history:
 * $Log: clntStrmSock.c,v $
 * Revision 1.3  1994/08/04  13:26:53  vanandel
 * added include files to suppress compile warnings
 *
 * Revision 1.2  1994/07/12  20:57:59  vanandel
 * use memset() for system 5 compat
 *
 * Revision 1.1  1994/03/09  18:46:39  vanandel
 * Initial revision
 *
 * Revision 1.1  1993/11/18  16:08:18  vanandel
 * Initial revision
 *
 * Revision 1.6  1992/09/25  15:34:21  vanandel
 * made host byte order independent for more portability
 *
 * Revision 1.5  1992/02/10  18:58:18  vanandel
 * changed timeout to mS
 *
 * Revision 1.4  1992/02/10  18:48:18  vanandel
 * added Unix non-blocking version
 *
 * Revision 1.3  1989/11/04  17:56:34  vanandel
 * fixed rcsid string
 *
 * Revision 1.2  89/11/04  17:52:55  vanandel
 * added copyright to file
 * 
 */

#ifdef TCL_MSDOS_PORT
#include "tkInt.h"
#include "tkPort.h"
#include <winsock.h>
#include "localTypes.h"
#else
#ifdef VX
#include "in.h"
#include "socket.h"
#include "sockLib.h"
#include "hostLib.h"
#include "ioLib.h"
#include "string.h"	/* for bzero() */

#else
#include <stdio.h>
#include <unistd.h>
#include <memory.h>
#include <string.h>

#include "localTypes.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/errno.h>
#ifndef  FIONBIO
#include <sys/filio.h>
#endif
#endif
#endif /* TCL_MSDOS_PORT */


int clntStrmSock(host,port)
	char *host;
	int port;

{
    struct sockaddr_in	serverAddr;		/* server's address */
#ifdef TCL_MSDOS_PORT
    SOCKET clientSock;
#else
    int clientSock;
#endif

    /* Zero out the sock_addr structures. */
    /* This MUST be done before the socket call. */

#ifdef TCL_MSDOS_PORT
    memset((char *)&serverAddr, 0, sizeof (serverAddr));
#else
#ifdef BZERO
    bzero ((char *)&serverAddr, sizeof (serverAddr));
#else
    memset(&serverAddr, 0, sizeof (serverAddr));
#endif
#endif

    /* Open the socket. */
    /* Use ARPA Internet address format and stream sockets. */

    clientSock = socket (AF_INET, SOCK_STREAM, 0);
#ifdef TCL_MSDOS_PORT
    if (clientSock == INVALID_SOCKET) {
	(void)closesocket (clientSock);
	return(ERROR_RETURN);
    }
#else
    if (clientSock == ERROR) {
	(void)close (clientSock);
	return(ERROR);
    }
#endif

    serverAddr.sin_addr.s_addr  = hostGetByName(host);

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port   = htons(port);	

#ifdef TCL_MSDOS_PORT
    if (connect(clientSock,(struct sockaddr *)&serverAddr,sizeof(serverAddr))
	==SOCKET_ERROR) {
	(void )closesocket (clientSock);
	return (ERROR_RETURN);
    }
#else
    if (connect(clientSock,(struct sockaddr *)&serverAddr,sizeof(serverAddr))
	==ERROR) {
	(void )close (clientSock);
	return (ERROR);
    }
#endif
    return(clientSock);
}

/*
 * this version of clntStrmSock() allows specifying how long to wait
 * before timing out on the connection request
 * only implemented for Unix version, right now
 */

int clntStrmSock2(host,port, block_time)
	char *host;
	int port;
	int block_time;		/* in milliSeconds */

{
    struct sockaddr_in	serverAddr;		/* server's address */
#ifdef TCL_MSDOS_PORT
    SOCKET clientSock;
#else
    int clientSock;
#endif
#ifndef VX
#ifdef TCL_MSDOS_PORT
    u_long arg;
#else
    int arg;
#endif
    fd_set fdset;
    struct timeval timeout;
    extern int errno;
#endif

    /* Zero out the sock_addr structures. */
    /* This MUST be done before the socket call. */

#ifdef TCL_MSDOS_PORT
    memset((char *)&serverAddr, 0, sizeof (serverAddr));
#else
#ifdef BZERO
    bzero ((char *)&serverAddr, sizeof (serverAddr));
#else
    memset(&serverAddr, 0, sizeof (serverAddr));
#endif
#endif

    /* Open the socket. */
    /* Use ARPA Internet address format and stream sockets. */

    clientSock = socket (AF_INET, SOCK_STREAM, 0);
#ifdef TCL_MSDOS_PORT
    if (clientSock == INVALID_SOCKET) {
	return(ERROR_RETURN);
    }
#else
    if (clientSock == ERROR) {
	return(ERROR);
    }
#endif
#ifndef VX
#ifdef TCL_MSDOS_PORT
    arg = 1L;
#else
    arg = 1;
#endif
    /* set NO-delay, so we timeout quickly if remote side isn't responding */

#ifdef TCL_MSDOS_PORT
    if (ioctlsocket(clientSock, FIONBIO, &arg) == SOCKET_ERROR)
    {
	return(ERROR_RETURN);
    }
#else
    if (ioctl(clientSock, FIONBIO, &arg) < 0)
    {
	fprintf(stderr, "ioctl failed\n");
	return(ERROR);
    }
#endif
#endif

    serverAddr.sin_addr.s_addr  = hostGetByName(host);

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port   = htons(port);	

#ifdef TCL_MSDOS_PORT
    if (connect(clientSock,(struct sockaddr *)&serverAddr,sizeof(serverAddr))
	==SOCKET_ERROR)
#else
    if (connect(clientSock,(struct sockaddr *)&serverAddr,sizeof(serverAddr))
	==ERROR)
#endif
    {
#ifndef VX
	/* with NON-BLOCK I/O connect doesn't happen instantly, 
	* so we'll wait briefly */
#ifdef TCL_MSDOS_PORT
	if (WSAGetLastError() ==  WSAEINPROGRESS)
#else
	if (errno ==  EINPROGRESS)
#endif
	{
	    FD_ZERO(&fdset);
	    FD_SET(clientSock, &fdset);
	    timeout.tv_sec = block_time/1000;
	    timeout.tv_usec = (block_time % 1000) * 1000;
	    /* if the connection doesn't timeout, we're connected */
#ifdef TCL_MSDOS_PORT
	    if (select( FD_SETSIZE, NULL, &fdset, NULL, &timeout) !=
		SOCKET_ERROR)
#else
	    if (select( FD_SETSIZE, NULL, &fdset, NULL, &timeout) >= 0)
#endif
	    {
		/* now,restore the normal blocking function on the descriptor 
		 * so that reads can block without returning error
		 */
		arg = 0;

#ifdef TCL_MSDOS_PORT
		if (ioctlsocket(clientSock, FIONBIO, &arg) == SOCKET_ERROR)
		{
		    return(ERROR_RETURN);
		}
#else
		if (ioctl(clientSock, FIONBIO, &arg) < 0)
		{
		    fprintf(stderr, "ioctl failed\n");
		    return(ERROR);
		}
#endif
		return(clientSock);
	    }
	}

#endif
#ifdef TCL_MSDOS_PORT
	(void )closesocket (clientSock);
	return (ERROR_RETURN);
#else
	(void )close (clientSock);
	return (ERROR);
#endif
    }
    return(clientSock);
}
