#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 {
    struct sockaddr_in addr;
    int done;
} target;

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

static void
CleanUp()
{
    close(sock);
    sock = 0;
}

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);
    }
    numTargets = i;
    return 0;
}

static int
SendMsgs()
{
    static char msg[] = "hello world";
    int i, len = sizeof(msg);
    
    for (i = 0; i < numTargets; i++) {
	if (targetTable[i].done) continue;
	if (len != sendto(sock, msg, len, 0, (struct sockaddr *) 
			  &targetTable[i].addr, sizeof(targetTable[i].addr))) {
	    perror("sendto");
	    return -1;
	}
    }
    return 0;
}

static int
RecvMsg()
{
    char buffer[128];
    int i, len, fromLen = sizeof(struct sockaddr_in);
    struct sockaddr_in from;
    
    len = recvfrom(sock, buffer, sizeof(buffer), 0,
		   (struct sockaddr *) &from, &fromLen);
    if (len == -1) {
	perror("recvfrom");
	return -1;
    }
    for (i = 0; i < numTargets; i++) {
	if (! targetTable[i].done 
	    && from.sin_addr.s_addr == targetTable[i].addr.sin_addr.s_addr) {
	    targetTable[i].done = 1;
	    break;
	}
    }
    fprintf(stdout, "%s\tok\n", inet_ntoa(from.sin_addr));
    return 0;
}

int
main(argc, argv)
    int argc;
    char **argv;
{
    int i, n; fd_set fds;
#ifdef RETRY
    struct timeval timeout = { 0, 100000 };
#endif

    if (GetTargets(argc, argv) < 0) {
	return 1;
    }

    sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (sock == -1) {
	perror("socket");
	return 2;
    }
    
    if (SendMsgs() == -1) {
	CleanUp();
	return 4;
    }

    while (1) {
	for (i = 0; i < numTargets; i++) {
	    if (! targetTable[i].done) break;
	}
	if (i == numTargets) break;

	FD_ZERO(&fds);
	FD_SET(sock, &fds);
#ifdef RETRY
	n = select(sock + 1, &fds, NULL, NULL, &timeout);
#else
	n = select(sock + 1, &fds, NULL, NULL, NULL);
#endif
	if (n == -1) {
	    perror("select");
	    CleanUp();
	    return 5;
	}
#ifdef RETRY
	if (n == 0) {
	    if (SendMsgs() == -1) {
		CleanUp();
		return 4;
	    }
	}
#endif
	if (RecvMsg() == -1) {
	    CleanUp();
	    return 7;
	}
    }

    CleanUp();
    return 0;
}

