/*
 * ipcfind is a program to locate IPC@CHIP systems in a local network.
 * 
 * It broadcasts a UDP packet to port 8001 and prints the results from
 * the IPCs. 
 * 
 * Author: Christian Decker (cdecker@teco.edu)
 * 		   TecO - University of Karlsruhe, Germany
 * 		   
 * Licence: GPL
 * 
 * http://www.teco.edu/~cdecker/webchip/
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

/* port the FINDSTR is sent to via broadcast */
#define BCPORT 8001 
/* the address the FINDSTR is sent to */
#define BCADDRESS "255.255.255.255"
/* a IPC responses with its IP number and name etc. if it gets this string*/
#define FINDSTR "0 1 "

/* real timeout = TIMEOUT * TIMESTEP 
 * TIMESTEP is in useconds
 */
#define TIMESTEP 500000
#define TIMEOUT 10

#define FALSE 0
#define TRUE 1

int main(int argc, char* argv[]) { 

	int sock, lenClient;
	struct sockaddr_in client; 
	struct hostent *hp;
	char buf[255]; /* receive buffer */
	int i, sent, rec, optval;
	int time; /* actual time count */
	int id[255]; /* id which were found (used for duplicate finding) */
	int id_counter = 0; /* counter for id array */
	int ipc_id; /* actual found IPC id */
	int dup = FALSE; /* TRUE, if a duplicate was found */

   	/* open a UDP socket */ 
	sock = socket( AF_INET, SOCK_DGRAM, 0 );  

	if (sock == -1) {
		perror("opening DATAGRAM socket !!!"); exit(1);
	}


	/* set socket parameter */
	fcntl(sock, F_SETFL, O_NONBLOCK); /* socket is non blocking */	

	/* this permits a datagram broadcast */
	optval = 1;
	setsockopt(sock, SOL_SOCKET,  SO_BROADCAST, &optval, sizeof(optval));
	
	hp = gethostbyname(BCADDRESS);
   
	if (hp == (struct hostent *) 0) {
		fprintf(stderr, "unknown host \n"); 
		exit(2);
	}

	client.sin_family = AF_INET;

	memcpy( (char *) &client.sin_addr, (char *) hp->h_addr, hp->h_length );
   
	client.sin_port = htons ((unsigned int) BCPORT);

	/* send FINSTR to address BCADDRESS to port BCPORT */
	if ( (sent = sendto(sock, FINDSTR, strlen(FINDSTR), 0, (struct sockaddr*) &client, sizeof(client))) == -1 ) {
		perror("sending DATAGRAM socket name !!!");
	}

	lenClient =sizeof(client);
    
	/* receive data from separate IPCs */
	time = 0;
	while (time < TIMEOUT) {
		if ( (rec = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &client, &lenClient )) == -1 ) {
			if (errno != EAGAIN) { /* there is really an error */
				perror("receiving DATAGRAM socket name !!!");
			}
		} else { /* we've received something */

			/* for duplicate finding */
			dup = FALSE;
			sscanf(buf, "%d", &ipc_id);
			for (i = 0; i < id_counter; i++) {
				if (id[i] == ipc_id) {
					dup = TRUE;
				}
			}
			   		
			if (!dup) { /* it's not a duplicate - print it! */
				id[id_counter++] = ipc_id;
				for (i = 0; i < rec; i++) {
					printf("%c", buf[i]);
				} 
			}

			if (rec > 0 && (!dup)) { /* there was an output string and no duplicate before */
				printf("\n");
			}
		}
		time++; /* next time cycle */
		usleep(TIMESTEP); /* sleep in micro seconds */
	}
   
	close( sock );
	return 0;
}

