/* Solaris: cc  client.c -lnsl -lsocket       */
/* Linux  : cc  client.c                      */
#include <stdio.h>
#include <stdlib.h>

#if defined(_MSC_VER)
#   define WindowsNT
#endif

#if defined WindowsNT
/*  Windows NT */
#  include <io.h>
#  include <winsock2.h>
#  define SOCKET_T SOCKET
#  define CLOSE(x) closesocket(x)
#else
/*  Unix */
#  include <netdb.h>
#  include <sys/types.h>
#  include <sys/socket.h>
#  include <netinet/in.h>
#  define SOCKET_T int
#  define INVALID_SOCKET -1
#  define CLOSE(x) close(x)
#endif


/*---------------------------------------
 * - XesOpenSocket
 *
 * Open a socket on a given host/port pair
 * char* host : remote host (in)
 * int port   : remote port (in)
 * SOCKET_T *p_socket_fd: opened socket (out)
 *
 * returns 0 for success, -1 else
 */
int XesOpenSocket(char* host,
		  int port,
		  SOCKET_T* pSocketFd) {
    struct sockaddr_in sockaddr;
    struct protoent* p_protoent;
    struct hostent*p_hostent; 
    struct in_addr addr;        
    char** p_h_addr_list;
 

    p_protoent = getprotobyname("tcp");
    if ( ! p_protoent ) {
        return -1;
    }
    
    *pSocketFd = socket(PF_INET, SOCK_STREAM, 0/*p_protoent->p_proto*/);
    if ( *pSocketFd == INVALID_SOCKET ) {
        return -1;
    }
    
    (void) memset((void *)&sockaddr, '\0', sizeof(struct sockaddr_in));
    sockaddr.sin_family = PF_INET;
    sockaddr.sin_port = htons((unsigned short) (port & 0xFFFF));
    
    p_hostent = gethostbyname(host);
    if (! p_hostent ) {
        return -1;
    }
    for ( p_h_addr_list = p_hostent->h_addr_list;
    *p_h_addr_list;
    p_h_addr_list++) {
        memcpy((void *) &addr,
            (void *) *p_h_addr_list,
            (size_t) p_hostent->h_length);
        sockaddr.sin_addr.s_addr = addr.s_addr;
        
        if ( connect(*pSocketFd, 
            (struct sockaddr *)&sockaddr, 
            sizeof(struct sockaddr)) != -1 ) {
            break;
        }
    }
    if ( ! *p_h_addr_list ) {
        return -1;
    }
    return 0;
}

/*
 * GetXesServerInfo
 * 
 * Opens and reads Xes .esp file to get host and port.
 *
 * char* fd: file to read (in)
 * char* pHost: filled with host name. Must has a sufficient size (out)
 * int* pPort: port number (out)
 *
 * returns 0 if success, -1 else
 */
int XesGetServerInfo(char* file, char* pHost, int* pPort) {
    FILE* fd;
    char buf[BUFSIZ];
    int status = -1;
    if ( (fd = fopen(file, "r")) == NULL ) {
	return -1;
    }
    while ( fgets(buf, BUFSIZ, fd) ) {
	if ( sscanf(buf, "%s%d", pHost, pPort) == 2 ) {
	    status = 0;
	    break;
	}
    }
    fclose(fd);
    return status;
}


int main(int argc, char** argv) {
    
    SOCKET_T socket_fd;
    char c;
    char buffer[BUFSIZ];
    int buf_len;
    char host[BUFSIZ];
    int port;

    
#if defined WindowsNT
#   define WSA_VERSION_REQD MAKEWORD(1, 1)

    WSADATA wsaData;
    
    if (WSAStartup(WSA_VERSION_REQD, &wsaData) != 0) {
        return 1;
    }
    if (wsaData.wVersion != WSA_VERSION_REQD) {
        return 1;
    }
#endif
    
    if ( XesGetServerInfo(argv[1], host, &port) == -1) {
	return 1;
    }
    fprintf(stderr, "Xes server: %s(%d)\n", host, port);
    if ( XesOpenSocket(host, port, &socket_fd) == -1) {
        return 1;
    }

    buf_len = 0;
    fprintf(stdout, "> ");
    fflush(stdout);
    while ( (c = getchar()) != EOF ) {
        buffer[buf_len++] = c;
        if ( buf_len == BUFSIZ || c == '\n' ) {
#if defined WindowsNT
	    fprintf(stderr, "send\n");
            if (send(socket_fd, buffer, buf_len, 0) == SOCKET_ERROR) {
                exit(1);    
            }
#else
	    if (write(socket_fd, (void*)buffer, buf_len) == -1) {
		exit (1);
	    }
#endif
            buf_len = 0;

	    fprintf(stdout, "> ");
	    fflush(stdout);

        }
    }
    
    CLOSE(socket_fd);
    return 0;
}
