#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef struct target {
    int sock;
    struct sockaddr_in addr;
} target;

static target targetTable[FD_SETSIZE];
static int numTargets = 0;

static void
CleanUp()
{
    int i;

    for (i = 0; i < FD_SETSIZE; i++) {
	if (targetTable[i].sock) close(targetTable[i].sock);
    }
}

static int
GetTargets(argc, argv)
    int argc;
    char **argv;
{
    int i;

    if (argc > FD_SETSIZE) {
	fprintf(stderr, "too many IPv4 addresses\n");
	return -1;
    }
    argc--; argv++;

    for (i = 0; i < argc; i++) {
	if (inet_aton(argv[i], &targetTable[i].addr.sin_addr) == 0) {
	    fprintf(stderr, "invalid IPv4 address \"%s\"\n", argv[i]);
	    return -1;
	}
	targetTable[i].addr.sin_port = htons(7);
	targetTable[i].sock = 0;
    }
    numTargets = i;
    return 0;
}

static int
SendMsgs()
{
    static char msg[] = "hello world";
    int i, len = sizeof(msg);

    for (i = 0; i < numTargets; i++) {
	if (len != send(targetTable[i].sock, msg, len, 0)) {
	    perror("send");
	    return -1;
	}
    }
    return 0;
}

static int
RecvMsg(i)
    int i;
{
    char buffer[128];
    int len;

    len = recv(targetTable[i].sock, buffer, sizeof(buffer), 0);
    if (len == -1) {
	perror("read");
	return -1;
    }
    if (len == 0) {
	fprintf(stderr, "lost connection to echo server?\n");
	return -1;
    }
    fprintf(stdout, "%s\tok\n", inet_ntoa(targetTable[i].addr.sin_addr));
    return 0;
}

int
main(argc, argv)
    int argc;
    char **argv;
{
    int i, n; fd_set fds;

    if (GetTargets(argc, argv) < 0) {
	return 1;
    }
    
    for (i = 0; i < numTargets; i++) {
	targetTable[i].sock = socket(PF_INET, SOCK_STREAM, 0);
	if (targetTable[i].sock == -1) {
	    perror("socket");
	    CleanUp();
	    return 2;
	}
	if (connect(targetTable[i].sock,
		    (struct sockaddr *) &targetTable[i].addr, 
		    sizeof(targetTable[i].addr)) == -1) {
	    perror("connect");
	    CleanUp();
	    return 3;
	}
    }

    if (SendMsgs() == -1) {
	CleanUp();
	return 4;
    }

    while (1) {
	FD_ZERO(&fds);
	for (i = 0, n = 0; i < numTargets; i++) {
	    if (targetTable[i].sock) {
		FD_SET(targetTable[i].sock, &fds);
		n = (targetTable[i].sock > n) ? targetTable[i].sock : n;
	    }
	}
	if (n == 0) break;

	n = select(n + 1, &fds, NULL, NULL, NULL);
	if (n == -1) {
	    perror("select");
	    CleanUp();
	    return 5;
	}

	for (i = 0; i < numTargets; i++) {
	    if (targetTable[i].sock && FD_ISSET(targetTable[i].sock, &fds)) {
		if (RecvMsg(i) == -1) {
		    CleanUp();
		    return 6;
		}
		close(targetTable[i].sock);
		targetTable[i].sock = 0;
	    }
	}
    }

    CleanUp();
    return 0;
}

