#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

jmp_buf         jmpbuf;

void
timeout(int sig)
{
    longjmp(jmpbuf, sig);
    return;
}


/*
 * attempt to create a connection to hostname on port 
 * will return -1 if takes longer than 'delay' seconds
 * on success, returns socket descriptor.
 */
int 
open_socket(char *hostname, int port, int delay)
{
    struct sockaddr_in sktin;
    struct hostent *host;
    int             mysock;

    /* allocate a socket */
    if ((mysock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
	return (-1);
    }
    memset(&sktin, 0, sizeof(sktin));
    sktin.sin_family = AF_INET;
    sktin.sin_port = htons(port);	/* set port number */

    if (setjmp(jmpbuf) == 0) {
	signal(SIGALRM, timeout);
	alarm(delay);

	/* get ip for host */
	if ((host = gethostbyname(hostname)) != NULL)
	    memcpy(&sktin.sin_addr, host->h_addr, host->h_length);
	else if ((sktin.sin_addr.s_addr = inet_addr(hostname)) < 0) 
		return(-1); /* couldn't resolve, and it wasn't an ip */

	/* connect to socket */
	if (connect(mysock, (const struct sockaddr *) & sktin, sizeof(sktin)) < 0) {
	    /* connect failed */
	    return (-1);
	}
	alarm(0);
    } else {
	/* timeout from jmpbuf */
	return (-1);
    }

    return (mysock);
}



/*
 * This is a sorta-wrapper for the above function. Pass it a couple file 
 * descriptors, and it will open them as files for ya. 
 */
int 
fpopensocket(char *host, int port, int timeout, FILE ** sockfp_in, FILE ** sockfp_out)
{
    int             sock_in, sock_out;

    sock_in = open_socket(host, port, timeout);
    if (sock_in < 0)
	return (0);

    if ((*sockfp_in = fdopen(sock_in, "r")) == NULL)
	return (0);

    if (setvbuf(*sockfp_in, NULL, _IOLBF, 0))
	return (0);

    sock_out = dup(sock_in);

    if ((*sockfp_out = fdopen(sock_out, "w")) == NULL)
	return (0);

    return (1);
}
